HTML Variablen mit Doppelleben?

cumulonimbus8

Fleet Admiral
Registriert
Apr. 2012
Beiträge
18.403
Moin!

Warum ändert sich hier auch die Variabel d1?
HTML:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <title></title>

<script type="text/javascript">
(function(){
var Meldung;
var d0;
var d1
})();
</script>

  </head>
  <body>

<span id="Anzeige1"></span>
<br>
<span id="Anzeige2"></span>

<script type="text/javascript">
var exdays = 19;
(function(){
d0 = new Date();
d1 = d0;
document.getElementById("Anzeige1").innerHTML = d0+" | "+d1;
d0.setTime(d0.getTime() + (exdays*24*60*60*1000));
document.getElementById("Anzeige2").innerHTML = d0+" | "+d1;
})();
</script>

  </body>
</html>

Dies ist mir zufällig untergekommen - und ich sehe keine Erklärung.
Lade ich die Datei in den Browser sehe ich in der ersten Zeile beides Mal heute (25.8.) und in der zweiten Zeile das Datum in 19 Tagen (Freitag, der 13. … - es sollten eigentlich 10 Tage sein; krumme Finger) und dies ebenfalls zweimal.
Ich ändere aktiv aber nur d0. Wie kann sich da d1 einfach so mitändern?
Der plumpe Versuch d1 = d0+"" friert den Wert ein - was wiederum auch nicht begründet, dass nicht auch das geändert würde.

So was ist mir bei meinen bescheidenen Programmierungen noch nie passiert, wenn wäre es sicher aufgefallen wie hier auch (ich wollte mir einfach nur heute als Vergleich anzeigen lassen…)

Was geht hier vor?

CN8
 
ganz einfach, bei objekten in javascript wird nur die referenz auf die instanz übergeben und keine kopie. daher sind d0 und d1 jeweils die referenz auf die selbe Date() instanz im speicher..

du musst also d0 und d1 ein eigenes new Date() zuweisen. dann hast du auch zwei unabhängige instanzen.
 
  • Gefällt mir
Reaktionen: kim88, mental.dIseASe, BeBur und eine weitere Person
Es ist genau so wie Cai-pirinha geschrieben hat. Falls du dich zu dem Thema noch ein wenig einlesen magst, einfach etwas in der Art wie "Reference Types vs Primitive values" suchen.
 
Hmtja…
Ich würde es vermutlich nicht hinkriegen so eine Referenz zu erzeugen wenn ich so was wollte…

Also weist JS hier nicht Inhalte zu sondern ›nur‹ eine Referenz wenn ich nicht beim Zuweisen diese Funktion(alität) »zerbreche« (unterbreche).
OK, danke, da muss ich dann künftig aufpassen.

CN8
 
es gibt natürlich methoden, um objekte zu klonen. steht jquery zur verfügung, würde ich da z.b. $.extend({}, obj) machen, das kopiert das objekt "obj" in das erste objekt - hier übergeben wir in form von {} ein neues, leeres objekt.
dann unterscheidet man noch zwischen deep copy und shallow copy. deep copy kopiert das objekt auf allen ebenen, eine shallow copy erstellt zwar ein neues objekt aber die objekt-eigenschaften sind immer noch die selben referenzen. wenn ich also ein objekt habe, das irgendwo auf eine Date() instanz verweist, und dieses objekt shallow copy'e, dann ist die referenz auf das Date immer noch die gleiche. mache ich eine deep copy, dann habe ich auch eine unabhängige neue Date() instanz. verbildlicht als code:

Code:
var A, B;

A = { date: new Date(), text: "Hallo" };
A.date.setDate(10);

B = A; // A und B zeigen auf das selbe Objekt
B.date.setDate(15);
B.text = "Halllllllo";

console.log(A.text, A.date.getDate(), B.text, B.date.getDate()); // "Halllllllo", 15, "Halllllllo", 15

B.text = "Hallo";

B = $.extend({}, A); // shallow copy. A und B sind zwei verschiedene Objekte, die aber auf das gleiche "date" zeigen
B.date.setDate(20);
B.text = "hAllLo";

console.log(A.text, A.date.getDate(), B.text, B.date.getDate()); // "Hallo", 20, "hAllLo", 20

B = $.extend(true, {}, A); // deep copy. A und B sind unabhängig
B.text = "hAllLo";
B.date.setDate(25);

console.log(A.text, A.date.getDate(), B.text, B.date.getDate()); // "Hallo", 20, "hAllLo", 25

auch ohne jquery kann man natürlich klonen. beispielsweise indem man ein objekt schlicht und einfach serialisiert und wieder deserialisiert. dabei gehen logischerweise die referenzen verloren und man hat nur noch die reinen puren werte, die beim deserialisieren wieder in objekte verpackt werden. JSON.stringify() und JSON.parse() lauten hier die beiden werte. das führt dann immer zu einer deep copy. ein bekannter nachteil ist allerdings genau die arbeit mit dem Date() objekt.. dieses wird nämlich zu einem formatierten zeit-string serialisiert und dann nicht wieder in ein Date() objekt deserialisiert sondern als string belassen.. tja... auch mit zirkulären verweisen wirds eher essig.

eine echte, fehlerfreie shallow copy mit JS bordmitteln erhält man mit var geclontesObjekt = Object.assign({], obj); - funktioniert wie das jquery $.extend und kopiert obj in das objekt, das als erster parameter übergeben wird (ein neues, leeres).

wie du siehst, es gibt für alles irgendwie einen weg, aber wie so oft in JS gibt es das ein oder andere zu beachten ;)
 
Sagen wir einfach, dass das Gewohnheit aus anderen Programmiersprachen ist/war - Variablen sind Variablen, keine Referenzen wenn sie nicht so deklariert sind.
CN8
 
Welche Programmiersprachen sind das denn?
Alle Sprachen, mit denen ich gearbeitet habe, unterscheiden zwischen Referenz- und Wertetypen. Und es wäre wohl speichertechnisch absoluter Blödsinn, potentiell riesige Objekte bei jeder Zuweisung und Übergabe in andere Objekte immer wieder neu zu klonen.

Ich möchte an dieser Stelle alle Interessierten auf dieses Video verweisen, was meiner Meinung nach den Stack und den Heap sehr gut erläutert. Es wird zwar anhand .NET erklärt, jedoch trifft das Prinzip auf viele Sprachen zu: .NET Stack and Heap (youtube.com)

Beim reinen Zuweisen von Variablen wird lediglich der Wert im Stack kopiert, aber nicht der Wert im Heap. Und da ein Date-Objekt nun einmal im Heap liegt, wird lediglich die im Stack gespeicherte Referenz kopiert. Und dann zeigen beide deine Variablen d0 und d1 auf das gleiche Element.
 
Zuletzt bearbeitet:

Ähnliche Themen

S
Antworten
9
Aufrufe
1.491
Smartass
S
Antworten
2
Aufrufe
898
Zurück
Oben