JavaScript-Objektmitglieder, die als Arrays prototypisch sind, werden von allen Klasseninstanzen gemeinsam genutzt

Lesezeit: 4 Minuten

Ist jemandem dieses Verhalten schon einmal aufgefallen? Das hat mich wirklich abgeschreckt … Ich hätte erwartet, dass prototypische Arrays für jede Klasseninstanz privat sind und nicht von allen Klasseninstanzen gemeinsam genutzt werden.

Kann jemand überprüfen, ob dies das richtige Verhalten ist, und dieses Verhalten vielleicht genauer erklären?

Beachten Sie den kommentierten Code und wie er das Verhalten des Skripts beeinflusst.

<html>
<head>

<script type="text/javascript">

function print_r( title, object ) {

    var output="";
    for( var key in object ) {

        output += key + ": " + object[ key ] + "\n";

    }

    output = title + "\n\n" + output;

    alert( output );

}

function Sandwich() {

    // Uncomment this to fix the problem
    //this.ingredients = [];

}

Sandwich.prototype = {

    "ingredients" : [],
    "addIngredients" : function( ingArray ) {

        for( var key in ingArray ) {

            this.addIngredient( ingArray[ key ] );

        }

    },
    "addIngredient" : function( thing ) {

        this.ingredients.push( thing );

    }

}

var cheeseburger = new Sandwich();
cheeseburger.addIngredients( [ "burger", "cheese" ] );

var blt = new Sandwich();
blt.addIngredients( [ "bacon", "lettuce", "tomato" ] );

var spicy_chicken_sandwich = new Sandwich();
spicy_chicken_sandwich.addIngredients( [ "spicy chicken pattie", "lettuce", "tomato", "honey dijon mayo", "love" ] );

var onLoad = function() {

    print_r( "Cheeseburger contains:", cheeseburger.ingredients );

};

</script>

</head>
<body onload="onLoad();">
</body>
</html>

Danke vielmals.

JavaScript Objektmitglieder die als Arrays prototypisch sind werden von allen Klasseninstanzen
Felix Klinge

Der Prototyp eines Objekts ist nur ein Objekt. Die Prototypeigenschaften werden von allen Objekten gemeinsam genutzt, die Erben von diesem Objekt. Es werden keine Kopien der Eigenschaften erstellt, wenn Sie eine neue Instanz einer “Klasse” (Klassen existieren sowieso nicht in JS) erstellen, dh ein Objekt, das vom Prototyp erbt.

Es macht nur einen Unterschied, wie Sie diese geerbten Eigenschaften verwenden:

function Foo() {}

Foo.prototype = {
    array: [],
    func: function() {}
}

a = new Foo();
b = new Foo();

a.array.push('bar');
console.log(b.array); // prints ["bar"]

b.func.bar="baz";
console.log(a.func.bar); // prints baz

In all diesen Fällen arbeiten Sie immer mit demselben Objekt.

Aber wenn du zuordnen ein Wert für eine Eigenschaft des Objekts, wird die Eigenschaft für das Objekt selbst festgelegt/erstellt, nicht für seinen Prototyp, und wird daher nicht geteilt:

console.log(a.hasOwnProperty('array')); // prints false
console.log(a.array); // prints ["bar"]
a.array = ['foo'];
console.log(a.hasOwnProperty('array')); // prints true
console.log(a.array); // prints ["foo"]
console.log(b.array); // prints ["bar"]

Wenn Sie für jede Instanz eigene Arrays erstellen möchten, müssen Sie dies im Konstruktor definieren:

function Foo() {
    this.array = [];
}

denn hier, this bezieht sich auf new Objekt, das beim Aufruf generiert wird new Foo().

Die Faustregel lautet: Beispiel-spezifischen Daten sollten zugeordnet werden Beispiel innerhalb der Konstrukteur, geteilt Daten (wie Methoden) sollten dem zugeordnet werden Prototyp.


Vielleicht möchten Sie lesen Details des Objektmodells die Unterschiede zwischen klassenbasierten und prototypbasierten Sprachen beschreibt und wie Objekte tatsächlich funktionieren.

Aktualisieren:

Sie können auf den Prototyp eines Objekts zugreifen über Object.getPrototypeOf(obj) (Funktioniert möglicherweise nicht in sehr alten Browsern) und Object.getPrototypeOf(a) === Object.getPrototypeOf(b) gibt Ihnen true. Es ist das gleiche Objekt, auch bekannt als Foo.prototype.

  • Hmm… Ja, das macht Sinn. Ich habe den Fehler gemacht, zu erwarten, dass der Prototyp wie eine Klassendefinition funktionieren würde. Das Verwirrende ist, dass wenn Foo.prototype.intValue = 5 ist und Sie b.intValue = 4 sagen, a.intValue immer noch = 5 ist. Es gilt also nur für die Objekt-/Array-Mitglieder der Klasse.

    – Dan

    13. Dezember 2010 um 2:28 Uhr


  • Dann wieder, wenn Sie b.array = sagen [‘whatever’], dann ändert sich a.array auch nicht. Explizite Zuweisungen mit dem Operator “=” überschreiben also prototypische Eigenschaften eines instanzierten Objekts.

    – Dan

    13. Dezember 2010 um 2:34 Uhr

  • @Dan: Nein, das habe ich auch in meinem Code gezeigt a.array = ['foo']; wird den Prototypen nicht verändern. Aber in Ihrem Fall mit der Ganzzahl und in meinem Fall mit dem Array weisen Sie einer Eigenschaft einen völlig neuen Wert zu. Und wenn Sie dies tun, wird die Eigenschaft auf das tatsächliche Objekt festgelegt. Aber wenn doch a.array.push(1)Du bist nicht Wenn Sie eine Eigenschaft festlegen, rufen Sie nur eine Methode in dem Array auf, das in enthalten ist a.array. Sie ändern die Referenz nicht.

    – Felix Klinge

    13. Dezember 2010 um 2:35 Uhr

  • Ja, tut mir leid, das meinte ich, als ich sagte: “Prototyp-Eigenschaften eines instanzierten Objekts überschreiben” – Sie wirken sich in diesem Fall auf das eigentliche Objekt und nur auf diese Instanz aus. Vielen Dank auch für den Link zu den Details des Objektmodells. Das muss ich mir mit einem feinen Kamm durchlesen.

    – Dan

    13. Dezember 2010 um 2:36 Uhr


  • @Dan: Dein zweiter Kommentar ist absolut richtig, ich konnte es nur nicht so gut ausdrücken 😉

    – Felix Klinge

    13. Dezember 2010 um 2:36 Uhr


Das Verhalten ist korrekt.
[] übersetzt wird new Array() zur Laufzeit, aber es wird immer nur ein solches Array erstellt.

Mit anderen Worten, Obj.prototype = {...} wird wie jede andere Zuweisung ausgeführt.

JavaScript Objektmitglieder die als Arrays prototypisch sind werden von allen Klasseninstanzen
Ferralucho

Wenn Sie das tun var exp1 = new C()JavaScript-Sets exp1.[[Prototype]] = C.prototype. Wenn Sie dann auf Eigenschaften der Instanz zugreifen, prüft JavaScript zuerst, ob sie direkt auf diesem Objekt vorhanden sind, und wenn nicht, schaut es hinein [[Prototype]]. Das bedeutet, dass alle Dinge, die Sie im Prototyp definieren, effektiv von allen Instanzen gemeinsam genutzt werden, und Sie können sogar später Teile des Prototyps ändern und die Änderungen in allen vorhandenen Instanzen erscheinen lassen.

923990cookie-checkJavaScript-Objektmitglieder, die als Arrays prototypisch sind, werden von allen Klasseninstanzen gemeinsam genutzt

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy