Forum: PC-Programmierung javascript: string.push() ändert ALLE Daten


von ich (Gast)


Lesenswert?

Ich habe ein Verständisproblem mit dem Befehl push() in Javascript. Um 
es besser aufzuzeigen, hier mal ein kleines Beispielprogramm:
1
let materialListObject_t =
2
{
3
    background: "red",
4
    text: "text",
5
    subText: "subText"
6
}
7
8
console.log('======================================')
9
var alerts = [ 
10
    {num : 1, app:'helloworld',message:'message'},
11
    {num : 2, app:'helloagain',message:'another message'} 
12
]
13
console.log(alerts)
14
15
console.log('======================================')
16
alerts.push({num : 3, app:'helloagain_again',message:'yet another message'});
17
console.log(alerts)
18
19
console.log('======================================')
20
let materialListObject = materialListObject_t;
21
alerts.push(materialListObject);
22
console.log(alerts)
23
24
console.log('======================================')
25
materialListObject.text = '#################';
26
alerts.push(materialListObject);
27
console.log(alerts)


Mein Problem bezieht sich auf den letzten Abschnitt. Der Bereich, in dem 
der String '########' geschrieben wird. Bis vor diesem Punkt, werden 
meine Daten wie erwartet in das Object "alerts" angehängt. Das passt. 
Aber im letzten Block werden nicht einfach neue Daten angehängt, sondern 
zusätzlich auch die bestehenden Daten überschrieben.
Kann mir jemand sagen warum das passiert? Ich dachte es wird mit push() 
immer nur angehängt.


log-output:
1
23:32:45.537  info  javascript.0 (1484) script.js.common.zeit_wecker_kalender.kalender.getAlarmClockFromICalCalendar: ======================================
2
23:32:45.538  info  javascript.0 (1484) script.js.common.zeit_wecker_kalender.kalender.getAlarmClockFromICalCalendar: [{'num':1,'app':'helloworld','message':'message'},{'num':2,'app':'helloagain','message':'another message'}]
3
23:32:45.538  info  javascript.0 (1484) script.js.common.zeit_wecker_kalender.kalender.getAlarmClockFromICalCalendar: ======================================
4
23:32:45.539  info  javascript.0 (1484) script.js.common.zeit_wecker_kalender.kalender.getAlarmClockFromICalCalendar: [{'num':1,'app':'helloworld','message':'message'},{'num':2,'app':'helloagain','message':'another message'},{'num':3,'app':'helloagain_again','message':'yet another message'}]
5
23:32:45.540  info  javascript.0 (1484) script.js.common.zeit_wecker_kalender.kalender.getAlarmClockFromICalCalendar: ======================================
6
23:32:45.540  info  javascript.0 (1484) script.js.common.zeit_wecker_kalender.kalender.getAlarmClockFromICalCalendar: [{'num':1,'app':'helloworld','message':'message'},{'num':2,'app':'helloagain','message':'another message'},{'num':3,'app':'helloagain_again','message':'yet another message'},{'background':'red','text':'text','subText':'subText'}]
7
23:32:45.541  info  javascript.0 (1484) script.js.common.zeit_wecker_kalender.kalender.getAlarmClockFromICalCalendar: ======================================
8
23:32:45.542  info  javascript.0 (1484) script.js.common.zeit_wecker_kalender.kalender.getAlarmClockFromICalCalendar: [{'num':1,'app':'helloworld','message':'message'},{'num':2,'app':'helloagain','message':'another message'},{'num':3,'app':'helloagain_again','message':'yet another message'},{'background':'red','text':'#################','subText':'subText'},{'background':'red','text':'#################','subText':'subText'}]

von Experte (Gast)


Lesenswert?

ich schrieb:
> Aber im letzten Block werden nicht einfach neue Daten angehängt, sondern
> zusätzlich auch die bestehenden Daten überschrieben.
> Kann mir jemand sagen warum das passiert?

Ja.

Die Datentypen Boolean, Null, Undefined, Number und String, sind in 
Javascript unveränderliche Datentypen.

Der Datentyp Objekt (und Array) hingegen ist ein veränderlicher 
Datentyp.

Wenn Du einer Variablen in Javascript ein Objekt "zuweist", wird ein 
Zeiger auf das Objekt in die Variable gespeichert, und nicht das 
Objekt selbst.

Wenn Du nun diese Variable (mit einem Zeiger auf ein ein Objekt) in eine 
andere kopierst, wird der Zeiger kopiert, aber nicht das Objekt.

D.h. wenn Du folgendes schreibst:
1
  let a, b;
2
  
3
  a = { msg: "Hallo, Welt!" };
4
  b = a;

Hast Du anschließend zwei Variablen, aber nur ein Objekt. Beide 
Variablen, a und b, zeigen auf das selbe, eine Objekt.

Wenn Du nun das Objekt änderst, egal über welchem "Zeiger" (a oder b), 
veränderst Du eben dieses eine Objekt.

von Experte (Gast)


Lesenswert?

Achso, Du willst aber zwei Objekte erzeugen:
1
 let a, b;
2
3
 a = { msg: "Hallo, Welt!" };
4
 b = { msg: "Hallo, Welt!" };

Hier hast Du nun zwei Variablen und zwei Objekte. Jede Variable zeigt 
auf ein anderes Objekt. Zufälligerweise haben beide Objekte aber den 
gleichen Inhalt.

Ein kleines Testprogramm verdeutlicht das:
1
  let a, b;
2
   
3
  a = { msg: "Hallo, Welt!" };
4
  b = a;
5
  console.log(a === b);
6
7
  a = { msg: "Hallo, Welt!" };
8
  b = { msg: "Hallo, Welt!" };
9
  console.log(a === b);

Probiere es aus!

von ich (Gast)


Lesenswert?

Danke schön für die ausführliche Erklärung. Konnte es nun auch 
verstehen.

Gibt es denn irgend eine andere Möglichkeit ein Objekt durch kopieren 
komplett neu zu erstellen?
In meinem Skript wollte ich eigentlich ein Objekt als template 
erstellen. Dieses Template sollte dann im laufenden Betrieb 
unterschiedlich oft vervielfältigt werden.

von Εrnst B. (ernst)


Lesenswert?

ich schrieb:
> Gibt es denn irgend eine andere Möglichkeit ein Objekt durch kopieren
> komplett neu zu erstellen?

Quick&Dirty für plain objects:

const clonedObject=JSON.parse(JSON.stringify(sourceObject));

("Quick" bezieht sich auf den Implementierungs-Aufwand, nicht die 
Laufzeit)


Ansonsten hört sich dein Plan eher nach einem OOP-Fall an, also

class MeineBasis {
 ...
}
class Irgendwas extends MeineBasis {
 ...
}
const instanz1=new Irgendwas;
const instanz2=new MeineBasis;
const instanz3=new Irgendwas;

usw...

von 🐧 DPA 🐧 (Gast)


Lesenswert?

ich schrieb:
> Gibt es denn irgend eine andere Möglichkeit ein Objekt durch kopieren
> komplett neu zu erstellen?

Nein. Man kann keine perfekte & vollständige deep copy eines beliebigen 
Objektes machen. Meistens ist das aber auch nicht nötig. Die 
JSON.parse(JSON.stringify(x)); Methode z.B. kann nur Zahlen, Nummern, 
Arrays, und Typenlose objekte, ohne Rekursion. Oft genügt sowas aber. 
Manchmal genügt sogar eine shallow copy, schau dir mal Object.assign und 
den spread operator an. Und dann gibt es noch Object.create, statt einer 
Kopie erzeugt das eine art overlay, indem es die Prototypchain ausnutzt.

Für deine Zwecke wird aber wohl eine klasse besser geeignet sein, oder 
sogar einfach eine Funktion, die das Objekt erstellt:
1
function createBla(){
2
  return { a:1, b:2 };
3
}
4
5
let x=createBla();
6
let y=createBla();

von Experte (Gast)


Lesenswert?

ich schrieb:
> Gibt es denn irgend eine andere Möglichkeit ein Objekt durch kopieren
> komplett neu zu erstellen?

Für Deinen Fall funktioniert der Spread-Operator sehr gut:
1
const template = { app: "Meine Super-App", message: "started" }
2
3
const a1 = { ...template, text: "Hallo, Welt!" };
4
const a2 = { ...template, text: "Hallo, Welt!" };
5
6
const b = { ...template, text: "Drittes Objekt" };
7
const c = { ...template, text: "Viertes Objekt", message: "Andere Nachricht" };
8
9
console.log();
10
console.table({a1, a2, b, c});
11
console.log();
12
console.log(`Sind a1 und a2 die gleichen Objekte: ${a1 === a2}`);
13
console.log();

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.