Hallo Daniel,
wenn es denn unbedingt ein GLOBAL_VARS Objekt sein muss... es gibt andere Methoden (Module).
Wie auch immer. Das Pattern ist eigentlich dieses:
window.GLOBAL_VARS = window.GLOBAL_VARS || {};
GLOBAL_VARS.einObj = GLOBAL_VARS.einObj || {};
GLOBAL_VARS.einObj.i = 47;
GLOBAL_VARS || {}
- was heißt das? Schau ins Wiki unter "Was ist Wahrheit".
Wenn GLOBAL_VARS noch undefiniert ist, findet sich darin der Wert undefined
. Dieser Wert ist falsy, deswegen wertet der || Operator auch noch seine rechte Seite aus und liefert diesen Wert zurück. Mehr dazu im Wiki unter Wahrheitstabellen und Kurzschlussreaktionen.
Warum window.GLOBAL_VARS? Weil Du sonst eine Fehlermeldung bekommen kannst, dass es diese Variable nicht gibt. Insbesondere im strict mode. Und var GLOBAL_VARS
kannst Du ja nicht schreiben, wenn Du nicht weißt, ob die Variable schon da ist.
Dieses Hantieren mit ||
ist eine Spezialität von JavaScript. Das Ergebnis von ||
und &&
ist nicht true
oder false
, sondern der Wert des linken oder rechten Operanden. Und das nutzt man im oben gezeigten Pattern aus.
- Ist GLOBAL_VARS schon da, bleibt es, wie es ist. Ist es noch nicht da, wird es mit einem leeren Objektliteral initialisiert.
- Ist GLOBAL_VARS.einObj schon da, blebt es wie es ist. Ist es noch nicht da, wird es mit einem leeren Objektliteral initialisiert.
Und was ist mit deinem Schlussbeispiel?
GLOBAL_VARS.einObj = {}.i = 0;
Böse ist das. Böse und Gemein!
{} ist ein Objektliteral und erzeugt ein leeres Objekt, mitten im großen Datenhaufen (a.k.a. Heap). Ein Verweis darauf wird ganz oben auf den Wertestapel gelegt. {}.i=0
erzeugt in diesem leeren Objekt ein Property i und speichert darin den Wert 0. Nun kommt das Erbe der 1960er und der Sprache C - der Operator =
ist ein Operator wie alle anderen auch, relativ niedrig priorisiert und rechts-assoziativ. Rechts-assoziativ heißt, dass c = b = a
wie c = (b = a)
zu lesen ist, und nicht wie (c = b) = a
(was in JavaScript eh Blödsinn wäre, aber in C++... oh je!). In deinem Fall wird also zuerst {}.i=0
ausgeführt. Zum Erbe gehört auch dies: Jeder Operator Hat Ein Ergebnis. Auch der Zuweisungsoperator. Der Wert von {}.i = 0
ist der zugewiesene Wert, also 0. Dieser Wert ersetzt den Verweis auf das vorhin angelegte Objekt, und wird dann an GLOBAL_VARS.einObj
zugewiesen. Danach ist das Statement zu Ende. Dieses kleine Objekt, dem Du eine Eigenschaft i verpasst hast, hat nun keinen mehr, der sich für es interessiert. Und so schwimmt es einsam und traurig irgendwo im Heap herum, ohne eine Rettungsleine, bis der gierige Garbage Collector vorbeischwimmt und es verschlingt. Armes Objekt 😢.
Anders gesagt:
GLOBAL_VARS.einObj = 0;
tut genau das gleiche, ohne ein Waisenobjekt zu hinterlassen.
Rolf
sumpsi - posui - obstruxi