molily: pass by reference - verständnisproblem

Beitrag lesen

function funky (o) {
o = null;
}
var x = {};
funky(x);
alert(x);


> >   
> Offenbar wird eine interne Kopie angelegt, sobald die Parameter-Variable »o« überschrieben wird.  
  
In dem verlinkten Teil meiner Doku bringe ich verschiedene Sachen durcheinander. Das war ein Missverständnis meinerseits. Es ist nicht ganz falsch, aber auch nicht ganz richtig.  
  
Eine Variable enthält entweder einen Primitive Value oder eine Referenz auf ein Object. Es ist im Gegensatz zu anderen Sprachen in JavaScript nicht möglich, den Wert von Variablen zu ändern, welche einer Funktion übergeben werden. Dieses Konzept gibt es einfach nicht. Man kann keine »Variablen übergeben«. Man übergibt immer Werte. Der lokalen Funktionsvariable wird beim Aufrufen der Funktion der übergebene Wert zugewiesen. Beispiel mit Primitives:  
  
~~~javascript
function f (primitive) {  
   alert(primitive);  
   primitive = 2; // Ändert nicht p  
}  
var p = 1;  
f(p);  
alert(p); // bleibt 1

Der Wert ist hier ein Number-Primitive.

Bei Objects passiert im Grunde dasselbe. Jetzt muss man eigentlich nur wissen, dass Objects immer in Form von Referenzen vorliegen. Beim Übergeben wird also nur eine Referenz auf eine Speicherstelle übergeben. Die lokale Funktionsvariable enthält dann diese Referenz als Wert. Die REFERENZ wird KOPIERT, aber nicht das dahinterliegende Object.

function f (object) {  
   alert(object.prop);  
   object.prop = 321; // Das ist möglich  
   object = null; // Ändert nicht o  
}  
var o = { prop: 123 };  
f(o);  
alert(o); // bleibt dasselbe Object, wird NICHT null  
alert(o.prop); // 321

Hier gibt es zu jeder Zeit nur ein Object im Speicher.

Wenn JavaScript call by reference erlauben würde, müsste folgendes gehen:

function funky (o) {
o = null;
}
var x = {};
funky(x);
alert(x);

Die Zuweisung zu o kann hier aber niemals den Wert der Variable x ändern. Die Variable o ist nicht an die Variable x gebunden. Es ist einfach eine lokale Variable, die beim Funktionsaufruf mit dem übergebenen Wert gefüllt wird (hier eine Object-Referenz). Weist man ihr einen neuen Wert zu, so hat das auf das referenzierte Object keinen Einfluss.

ich bin leider schon seit ~3 Jahren im Status "Will mich mal irgendwann™ näher mit JS-Interna befassen" gefangen

Da kann ich nur die Lektüre von ECMA-262 in detail empfehlen.

Zu meiner Doku:

Primitives werden als Kopie an Funktionen übergeben, während Objekte als Referenzen auf dieselbe Speicherstelle (in anderen Programmiersprachen »Zeiger« genannt) übergeben werden.

Das ist soweit noch richtig.

Gegeben ist folgender Fall: Sie notieren ein Objekt als Variable. Dieses Objekt übergeben Sie einer Funktion und in der Funktion nehmen Sie Änderungen am Objekt vor, fügen ihm z.B. eine Eigenschaft hinzu.
Wenn das Objekt als Referenz übergeben wird, dann haben Sie nach dem Funktionsaufruf auf das geänderte Objekt Zugriff. Denn an beiden Stellen, innerhalb und außerhalb der Funktion, haben Sie Zugriff auf ein und dasselbe Objekt.
Wenn das Objekt als Primitive übergeben wird, dann haben Änderungen daran keine Auswirkung auf die Variable im ursprünglichen Kontext – es sei denn, die Funktion gibt einen Primitive zurück und Sie arbeiten mit dem Rückgabewert der Funktion weiter.

Das ist missverständlich und ich verwende hier unsaubere Terminologie (ich wollte es einfach halten, aber das geht hier nach hinten los).

Ein Objekt (Object) wird immer als Referenz übergeben. Sonst wäre es kein Object, sondern ein Primitive. Man kann sich nicht aussuchen, wie man ein Object übergibt. Ein Object als Primitive zu übergeben, geht nicht, es sei denn, man wandelt es explizit vorher um.

Einen Einfluss auf die VARIABLE im ursprünglichen Kontext hat man in beiden Fällen nicht.
Ein Object kann man ändern, man kann seine Eigenschaften ändern. Dann ist das geänderte Object auch überall dort verfügbar, wo Referenzen darauf existieren, denn durch Übergeben werden Objects nicht kopiert.
Bei Primitives gibt es diese Möglichkeit, »sie selbst« zu verändern, schlicht nicht - sie haben keine (dauerhaften) Eigenschaften. Mit einem Funktionsaufruf wird eine neue Schublade aufgemacht und ein einfacher Wert darin abgelegt. Legt man etwas anderes dort hinein, ändert sich nicht plötzlich der Inhalt anderer Schubladen in ganz anderen Schränken.

Mathias