Javascript Objekt wird immer überschrieben
ebody
- javascript
0 kai3451 Rolf B
0 Gunnar Bittersmann2 dedlfix
Hallo,
ich habe ein Objekt:
const objTableHeadings = {
Title: '',
Genre: '',
Tags: ''
};
Dieses Objekt füge ich als Element einem Array zu
arrData.push(objTableHeadings);
Anschließend füge ich dem Key 'Genre' einen Wert zu.
Ich füge dem Array ein weiteres Objekt als Element zu:
arrData.push(objTableHeadings);
Anschließend füge ich diesem 2. Element und dem Key 'Genre' einen Wert zu.
Gebe ich dann arrData[]
aus, enthalten die Keys beider Objekte den gleichen Wert. Der Wert vom 1. Objekt wurde überschrieben. Warum?
Gruß ebody
printf('Hallo %s!', ['Du', 'ihr', 'Welt', 'zusammen'][rand(0, 3)]);
Das Objekt referenziert immer objTableHeadings, egal wie oft du es ins Array einfügst. Daher werden Änderungen auch dort vorgenommen und von allen Referenzen diese Werte aufgerufen.
Zu wenig Zeit für eine genaue Erklärung, aber das sollte gehen:
const newTableHeadinsObj = Object.create(objTableHeadings);
arrData.push(newTableHeadinsObj);
/K
Hallo kai345,
newTableHeadinsObj = Object.create(objTableHeadings);
Ich bin nicht so sicher, ob das hier zielführend ist. Auf diesem Weg erzeugst Du ein leeres Objekt, das das objTableHeadings Objekt als Prototyp besitzt.
Das ist etwas anderes als eine Kopie. Die wird von Dedlfix' Beispiel erzeugt, setzt aber einen aktuellen Browser voraus (d.h. nicht den Internet Explorer). Dedlfix verwendet den ... Operator, der je nach Zusammenhang "Rest" oder "Spread" Operator genannt wird. Im vorliegenden Fall ist es "Spread" - ausbreiten. Die Eigenschaften von objTableHeadings
werden innerhalb von { } "ausgebreitet", d.h. verteilt, was dazu führt, dass JavaScript das wie ein Objektliteral auffasst, wo jede einzelne Eigenschaft aus objTableHeadings
im Objektliteral zugewiesen wird.
const foo = { a: 1, b: 2 };
const bar1 = { a: foo.a, b: foo.b },
bar2 = { ...foo };
console.log(bar1.a, bar1.b); // 1 2
console.log(bar1.hasOwnProperty("a")); // true
console.log(bar1.hasOwnProperty("b")); // true
console.log(bar2.a, bar2.b); // 1 2
console.log(bar2.hasOwnProperty("a")); // true
console.log(bar2.hasOwnProperty("b")); // true
foo.a = 99;
console.log(bar1.a, bar2.a); // 1 1
Das, was JavaScript bei bar1 und bar2 tut, ist exakt das gleiche. Die direkt in foo definierten Eigenschaften werden hergenommen und ins Objektliteral ausgebreitet. Deswegen gibt hasOwnProperty auch true aus.
Aber Object.create macht etwas anderes:
const foo = { a: 1, b: 2 };
const bar = Object.create(foo);
console.log(bar.a, bar.b); // 1 2
console.log(bar.hasOwnProperty("a")); // FALSE
console.log(bar.hasOwnProperty("b")); // FALSE
foo.a = 77;
foo.b = 88;
bar.a = 44;
console.log(bar.a, bar.b); // 44 88
console.log(bar.hasOwnProperty("a")); // TRUE
console.log(bar.hasOwnProperty("b")); // FALSE
Hier wird foo
zum Prototypen für bar
- die JavaScript-Grundlage für Objektvererbung. Das bedeutet: Wenn in bar eine Eigenschaft oder Methode gesucht wird, die in bar nicht existiert, schaut JavaScript in foo nach und holt sich den Wert von dort. Bei einer Zuweisung wird aber immer nach bar
geschrieben. Deswegen gibt hasOwnProperty zunächst FALSE für a und b aus, und deswegen schlägt die Änderung an foo.b auf bar durch.
Rolf
@@ebody
Gebe ich dann
arrData[]
aus, enthalten die Keys beider Objekte den gleichen Wert. Der Wert vom 1. Objekt wurde überschrieben. Warum?
Dein Array arrData
enthält zwei Zeiger auf einunddasselbe Objekt objTableHeadings
.
😷 LLAP
Tach!
const objTableHeadings = { Title: '', Genre: '', Tags: '' };
Dieses Objekt füge ich als Element einem Array zu
arrData.push(objTableHeadings);
Anschließend füge ich dem Key 'Genre' einen Wert zu.
Genauer gesagt: Der hat schon einen Wert, du änderst ihn nur. Hinzufügen wäre, wenn der alte Wert erhalten bliebe, was nicht der Fall ist.
Ich füge dem Array ein weiteres Objekt als Element zu:
arrData.push(objTableHeadings);
Wie bereits gesagt, du fügt das Objekt ein weiteres mal hinzu. Wenn du ein neues haben möchtest, musst du ein neues anlegen. Es kommt dabei darauf an, bis in welcher Tiefe es eine Kopie sein muss.
arrData.push({...objTableHeadings});
Das ist der einfachste Weg, eine Shallow Copy anzulegen. In deinem Beispiel sind die Eigenschaften alles Strings, also primitive Werte, die werden kopiert. Wenn es aber Objekte wären, würde lediglich eine weitere Referenz erstellt, die weiterhin auf das Original verweist.
Warum?
Das erklärt sich, wenn man die Hintergründe kennt, wie mit Variablen umgegangen wird. Eine Variable ist ein Container, in dem das System die Dinge verwaltet, die es dazu wissen muss. Primitive Werte steht direkt in diesem Container. Sie benötigen nur ein bis wenige Byte Speicherplatz und sind damit klein genug, direkt dort abgelegt zu werden. String können zwar länger sein, werden aber auch wie primitive Werte behandelt.
Objekte und Arrays sind keine primitiven Werte. Die eigentlichen Inhalte werden üblicherweise irgendwo in einem anderen Speicherbereich abgelegt. Im Variablencontainer kommt dann nur eine Referenz auf diese andere Speicherstelle zu liegen. Damit nicht unnötig Speicher verbraucht wird, ist es in den meisten Systemen so, dass lediglich die Referenzen weitergegeben werden, wenn man mit der Variable etwas anstellt. Sie zeigen ohne weitere Handlung also immer auf denselben Speicherbereich. Änderst du daran etwas, bekommst du diese Änderung natürlich auch über alle anderen Referenzen mit, die auf denselben Speicherbereich zeigen.
dedlfix.