webentwicklung-frage-antwort-db.com.de

Ist JavaScript eine Pass-by-Reference- oder eine Pass-by-Value-Sprache?

Die primitiven Typen (Zahl, Zeichenfolge usw.) werden als Wert übergeben, Objekte sind jedoch unbekannt, da beide als Wert übergeben werden können (falls wir annehmen, dass eine Variable, die ein Objekt enthält, tatsächlich eine Referenz auf das Objekt ist) ) und als Referenz übergeben (wenn wir berücksichtigen, dass die Variable zum Objekt das Objekt selbst enthält).

Obwohl es am Ende nicht wirklich wichtig ist, möchte ich wissen, wie die Argumente, die Konventionen überschreiten, richtig dargestellt werden. Gibt es einen Auszug aus der JavaScript-Spezifikation, der definiert, welche Semantik diesbezüglich gelten soll?

1286
Danail Nachev

Es ist interessant in JavaScript. Betrachten Sie dieses Beispiel:

function changeStuff(a, b, c)
{
  a = a * 10;
  b.item = "changed";
  c = {item: "changed"};
}

var num = 10;
var obj1 = {item: "unchanged"};
var obj2 = {item: "unchanged"};

changeStuff(num, obj1, obj2);

console.log(num);
console.log(obj1.item);
console.log(obj2.item);

Dies erzeugt die Ausgabe:

10
changed
unchanged
  • Wenn obj1 überhaupt keine Referenz ist, hat das Ändern von obj1.item keine Auswirkung auf obj1 außerhalb der Funktion.
  • Wenn das Argument eine richtige Referenz wäre, hätte sich alles geändert. num wäre 100 und obj2.item würde "changed" lesen.

Stattdessen wird das übergebene Element als Wert übergeben. Das Element, das als Wert übergeben wird, ist selbst eine Referenz. Technisch heißt das Call-by-Sharing .

In der Praxis bedeutet dies, dass, wenn Sie den Parameter selbst ändern (wie bei num und obj2), dies keinen Einfluss auf das Element hat, das in den Parameter eingegeben wurde. Wenn Sie jedoch die INTERNA des Parameters ändern, wird die Übertragung fortgesetzt (wie bei obj1).

1505
deworde

Es wird immer als Wert übergeben, aber für Objekte ist der Wert der Variablen eine Referenz. Aus diesem Grund bleiben diese Änderungen außerhalb der Funktion erhalten, wenn Sie ein Objekt übergeben und dessen Elemente ändern. Dies macht es aussehen wie Referenz übergeben. Wenn Sie den Wert der Objektvariablen jedoch tatsächlich ändern, werden Sie feststellen, dass die Änderung nicht fortbesteht, was beweist, dass sie tatsächlich vom Wert abweicht.

Beispiel:

function changeObject(x) {
  x = { member: "bar" };
  console.log("in changeObject: " + x.member);
}

function changeMember(x) {
  x.member = "bar";
  console.log("in changeMember: " + x.member);
}

var x = { member: "foo" };

console.log("before changeObject: " + x.member);
changeObject(x);
console.log("after changeObject: " + x.member); /* change did not persist */

console.log("before changeMember: " + x.member);
changeMember(x);
console.log("after changeMember: " + x.member); /* change persists */

Ausgabe:

before changeObject: foo
in changeObject: bar
after changeObject: foo

before changeMember: foo
in changeMember: bar
after changeMember: bar
430
Tim Goodman

Die Variable "hält" das Objekt nicht; es enthält eine Referenz. Sie können diesen Verweis einer anderen Variablen zuweisen, und jetzt verweisen beide auf dasselbe Objekt. Es wird immer als Wert übergeben (auch wenn dieser Wert eine Referenz ist ...).

Es gibt keine Möglichkeit, den Wert einer als Parameter übergebenen Variablen zu ändern. Dies wäre möglich, wenn JavaScript die Übergabe als Referenz unterstützt.

141
Shog9

Meine zwei Cent ... So verstehe ich das. (Fühlen Sie sich frei, mich zu korrigieren, wenn ich falsch liege)

Es ist Zeit, alles, was Sie über das Übergeben von Werten/Referenzen wissen, wegzuwerfen.

Da es in JavaScript keine Rolle spielt, ob es als Wert oder als Referenz übergeben wird oder was auch immer. Entscheidend ist die Mutation oder die Zuweisung der Parameter, die an eine Funktion übergeben werden.

OK, lassen Sie mich mein Bestes geben, um zu erklären, was ich meine. Angenommen, Sie haben ein paar Objekte.

var object1 = {};
var object2 = {};

Was wir getan haben, ist "Zuweisung" ... Wir haben den Variablen "object1" und "object2" 2 separate leere Objekte zugewiesen.

Nehmen wir an, wir mögen object1 besser ... Also "weisen" wir eine neue Variable zu.

var favoriteObject = object1;

Als nächstes entscheiden wir uns aus irgendeinem Grund, dass wir Objekt 2 besser mögen. Also machen wir einfach eine kleine Neuzuweisung.

favoriteObject = object2;

Es ist nichts mit object1 oder object2 passiert. Wir haben überhaupt keine Daten geändert. Alles, was wir getan haben, war, unser Lieblingsobjekt neu zuzuweisen. Es ist wichtig zu wissen, dass object2 und favoriteObject demselben Objekt zugewiesen sind. Wir können dieses Objekt über eine dieser Variablen ändern.

object2.name = 'Fred';
console.log(favoriteObject.name) // Logs Fred
favoriteObject.name = 'Joe';
console.log(object2.name); // Logs Joe

OK, jetzt schauen wir uns Primitive wie zum Beispiel Strings an

var string1 = 'Hello world';
var string2 = 'Goodbye world';

Wieder wählen wir einen Favoriten.

var favoriteString = string1;

Sowohl unsere favoriteString- als auch unsere string1-Variablen sind 'Hello world' zugeordnet. Was ist, wenn wir unseren favoriteString ändern wollen? Was wird passieren???

favoriteString = 'Hello everyone';
console.log(favoriteString); // Logs 'Hello everyone'
console.log(string1); // Logs 'Hello world'

Oh oh ... was ist passiert? Wir konnten string1 nicht ändern, indem wir favoriteString änderten ... Warum ?? Weil wir nicht change unseren String object haben. Alles, was wir getan haben, war "RE ASSIGN" der favoriteString Variable zu einem neuen String. Dies hat es im Wesentlichen von string1 getrennt. Im vorherigen Beispiel haben wir beim Umbenennen unseres Objekts nichts zugewiesen. (Nun, nicht für die - Variable selbst , ... wir haben die name -Eigenschaft jedoch einer neuen Zeichenfolge zugewiesen.) Stattdessen haben wir einfach das Objekt mutiert, das die Verbindungen beibehält zwischen den 2 Variablen und den zugrunde liegenden Objekten. (Auch wenn wir das Zeichenfolgenobjekt ändern oder mutieren wollten selbst , konnten wir dies nicht tun, da Zeichenfolgen tatsächlich unveränderlich sind in JavaScript.)

Nun zu Funktionen und der Übergabe von Parametern .... Wenn Sie eine Funktion aufrufen und einen Parameter übergeben, müssen Sie im Wesentlichen einer neuen Variablen eine "Zuweisung" geben, und dies funktioniert genauso, als ob Sie sie einfach mit zugewiesen hätten das Gleichheitszeichen (=).

Nehmen Sie diese Beispiele.

var myString = 'hello';

// Assign to a new variable (just like when you pass to a function)
var param1 = myString;
param1 = 'world'; // Re assignment

console.log(myString); // Logs 'hello'
console.log(param1);   // Logs 'world'

Nun das Gleiche, aber mit einer Funktion

function myFunc(param1) {
    param1 = 'world';

    console.log(param1);   // Logs 'world'
}

var myString = 'hello';
// Calls myFunc and assigns param1 to myString just like param1 = myString
myFunc(myString);

console.log(myString); // logs 'hello'

OK, jetzt wollen wir ein paar Beispiele geben, die stattdessen Objekte verwenden ... zuerst ohne die Funktion.

var myObject = {
    firstName: 'Joe',
    lastName: 'Smith'
};

// Assign to a new variable (just like when you pass to a function)
var otherObj = myObject;

// Let's mutate our object
otherObj.firstName = 'Sue'; // I guess Joe decided to be a girl

console.log(myObject.firstName); // Logs 'Sue'
console.log(otherObj.firstName); // Logs 'Sue'

// Now, let's reassign the variable
otherObj = {
    firstName: 'Jack',
    lastName: 'Frost'
};

// Now, otherObj and myObject are assigned to 2 very different objects
// And mutating one object has no influence on the other
console.log(myObject.firstName); // Logs 'Sue'
console.log(otherObj.firstName); // Logs 'Jack';

Nun das gleiche, aber mit einem Funktionsaufruf

function myFunc(otherObj) {

    // Let's mutate our object
    otherObj.firstName = 'Sue';
    console.log(otherObj.firstName); // Logs 'Sue'

    // Now let's re-assign
    otherObj = {
        firstName: 'Jack',
        lastName: 'Frost'
    };
    console.log(otherObj.firstName); // Logs 'Jack'

    // Again, otherObj and myObject are assigned to 2 very different objects
    // And mutating one object doesn't magically mutate the other
}

var myObject = {
    firstName: 'Joe',
    lastName: 'Smith'
};

// Calls myFunc and assigns otherObj to myObject just like otherObj = myObject
myFunc(myObject);

console.log(myObject.firstName); // Logs 'Sue', just like before

OK, wenn Sie diesen ganzen Beitrag durchlesen, haben Sie vielleicht jetzt ein besseres Verständnis dafür, wie Funktionsaufrufe in JavaScript funktionieren. Es spielt keine Rolle, ob etwas als Referenz oder als Wert übergeben wird ... Entscheidend ist Zuordnung vs. Mutation.

Jedes Mal, wenn Sie einer Funktion eine Variable übergeben, wird der Name der Parametervariable "zugewiesen", genau wie bei Verwendung des Gleichheitszeichens (=).

Denken Sie immer daran, dass das Gleichheitszeichen (=) Zuordnung bedeutet. Denken Sie immer daran, dass die Übergabe eines Parameters an eine Funktion in JavaScript auch eine Zuweisung bedeutet. Sie sind gleich und die beiden Variablen sind genau gleich miteinander verbunden (das heißt, sie sind es nicht, es sei denn, Sie rechnen damit, dass sie demselben Objekt zugeordnet sind).

Das "Ändern einer Variablen" wirkt sich nur dann auf eine andere Variable aus, wenn das zugrunde liegende Objekt mutiert ist (in diesem Fall haben Sie nicht die Variable, sondern das Objekt selbst geändert.

Es macht keinen Sinn, zwischen Objekten und Grundelementen zu unterscheiden, da dies genauso funktioniert, als ob Sie keine Funktion hätten und lediglich das Gleichheitszeichen zur Zuweisung einer neuen Variablen verwenden würden.

Der einzige Punkt ist, wenn der Name der Variablen, die Sie an die Funktion übergeben, mit dem Namen des Funktionsparameters identisch ist. In diesem Fall müssen Sie den Parameter in der Funktion so behandeln, als wäre er eine ganz neue Variable, die für die Funktion privat ist (da dies der Fall ist).

function myFunc(myString) {
    // myString is private and does not affect the outer variable
    myString = 'hello';
}

var myString = 'test';
myString = myString; // Does nothing, myString is still 'test';

myFunc(myString);
console.log(myString); // Logs 'test'
94
Ray Perea

Folgendes berücksichtigen:

  1. Variablen sind Zeiger zu Werten im Speicher.
  2. Wenn Sie eine Variable neu zuweisen, wird der Zeiger lediglich auf einen neuen Wert gesetzt.
  3. Das erneute Zuweisen einer Variablen wirkt sich niemals auf andere Variablen aus, die auf dasselbe Objekt zeigten

Damit, vergessen Sie "Referenz/Wert übergeben" Lass dich nicht von "Übergeben nach Referenz/Wert" hängen, weil:

  1. Die Begriffe werden nur verwendet, um das Verhalten einer Sprache zu beschreiben, nicht unbedingt die eigentliche zugrunde liegende Implementierung. Infolge dieser Abstraktion gehen kritische Details verloren, die für eine anständige Erklärung unerlässlich sind, was unweigerlich zu der gegenwärtigen Situation führt, in der ein einzelner Begriff das tatsächliche Verhalten nicht angemessen beschreibt und zusätzliche Informationen bereitgestellt werden müssen
  2. Diese Konzepte wurden ursprünglich nicht mit der Absicht definiert, insbesondere Javascript zu beschreiben, und daher sehe ich mich nicht gezwungen, sie zu verwenden, wenn sie nur die Verwirrung verstärken.

Um Ihre Frage zu beantworten: Zeiger werden übergeben.


// code
var obj = {
    name: 'Fred',
    num: 1
};

// illustration
               'Fred'
              /
             /
(obj) ---- {}
             \
              \
               1


// code
obj.name = 'George';


// illustration
                 'Fred'


(obj) ---- {} ----- 'George'
             \
              \
               1


// code
obj = {};

// illustration
                 'Fred'


(obj)      {} ----- 'George'
  |          \
  |           \
 { }            1


// code
var obj = {
    text: 'Hello world!'
};

/* function parameters get their own pointer to 
 * the arguments that are passed in, just like any other variable */
someFunc(obj);


// illustration
(caller scope)        (someFunc scope)
           \             /
            \           /
             \         /
              \       /
               \     /
                 { }
                  |
                  |
                  |
            'Hello world'

Einige abschließende Bemerkungen:

  • Es ist verlockend zu glauben, dass Primitive durch spezielle Regeln erzwungen werden, Objekte nicht, aber Primitive sind einfach das Ende der Zeigerkette.
  • Stellen Sie sich als letztes Beispiel vor, warum ein häufiger Versuch, ein Array zu löschen, nicht wie erwartet funktioniert.


var a = [1,2];
var b = a;

a = [];
console.log(b); // [1,2]
// doesn't work because `b` is still pointing at the original array
64
geg

Ein Objekt außerhalb einer Funktion wird an eine Funktion übergeben, indem auf das äußere Objekt verwiesen wird.

Wenn Sie diesen Verweis verwenden, um sein Objekt zu manipulieren, ist das Objekt außerhalb davon betroffen. Wenn Sie sich jedoch innerhalb der Funktion dazu entschieden haben, die Referenz auf etwas anderes zu verweisen, haben Sie das Objekt außerhalb überhaupt nicht beeinflusst, da Sie lediglich die Referenz auf etwas anderes umgeleitet haben.

23
user779764

Stellen Sie sich das so vor: Es ist immer von Wert. Der Wert eines Objekts ist jedoch nicht das Objekt selbst, sondern eine Referenz auf dieses Objekt.

Hier ist ein Beispiel, bei dem eine Zahl übergeben wird (ein primitiver Typ)

function changePrimitive(val) {
    // At this point there are two '10's in memory.
    // Changing one won't affect the other
    val = val * 10;
}
var x = 10;
changePrimitive(x);
// x === 10

Wenn Sie dies mit einem Objekt wiederholen, erhalten Sie unterschiedliche Ergebnisse:

function changeObject(obj) {
    // At this point there are two references (x and obj) in memory,
    // but these both point to the same object.
    // changing the object will change the underlying object that
    // x and obj both hold a reference to.
    obj.val = obj.val * 10;
}
var x = { val: 10 };
changeObject(x);
// x === { val: 100 }

Ein weiteres Beispiel:

function changeObject(obj) {
    // Again there are two references (x and obj) in memory,
    // these both point to the same object.
    // now we create a completely new object and assign it.
    // obj's reference now points to the new object.
    // x's reference doesn't change.
    obj = { val: 100 };
}
var x = { val: 10 };
changeObject(x);
// x === { val: 10}
19
Phil Mander

JavaScript ist immer pass-by-value; Alles ist vom Werttyp.

Objekte sind Werte und Mitgliedsfunktionen von Objekten sind Werte selbst (denken Sie daran, dass Funktionen in JavaScript erstklassige Objekte sind). Auch in Bezug auf das Konzept, dass alles in JavaScript ein Objekt ist; das ist falsch. Zeichenfolgen, Symbole, Zahlen, Boolesche Werte, Nullen und undefinierte Werte sind Primitive.

Gelegentlich können sie einige Elementfunktionen und -eigenschaften nutzen, die von ihren Basisprototypen geerbt wurden. Dies dient jedoch nur der Vereinfachung. Das bedeutet nicht, dass sie selbst Objekte sind. Versuchen Sie Folgendes als Referenz:

x = "test";
alert(x.foo);
x.foo = 12;
alert(x.foo);

In beiden Warnmeldungen finden Sie den Wert undefiniert.

14
Michael Roberts

Eine sehr detaillierte Erklärung zum Kopieren, Übergeben und Vergleichen nach Wert und Referenz finden Sie in dieses Kapitel des "JavaScript: The Definitive Guide" Buch.

Bevor wir das Thema der Manipulation von Objekten und Arrays durch Referenz verlassen, müssen wir einen Punkt der Nomenklatur klären.

Der Ausdruck "Referenzübergabe" kann mehrere Bedeutungen haben. Für einige Leser bezieht sich der Ausdruck auf eine Funktionsaufruftechnik, die es einer Funktion ermöglicht, ihren Argumenten neue Werte zuzuweisen und diese geänderten Werte außerhalb der Funktion sichtbar zu machen. Dies ist nicht die Art und Weise, wie der Begriff in diesem Buch verwendet wird.

Hiermit ist einfach gemeint, dass ein Verweis auf ein Objekt oder Array - nicht auf das Objekt selbst - an eine Funktion übergeben wird. Eine Funktion kann die Referenz verwenden, um Eigenschaften des Objekts oder der Elemente des Arrays zu ändern. Wenn die Funktion jedoch die Referenz mit einer Referenz auf ein neues Objekt oder Array überschreibt, ist diese Änderung außerhalb der Funktion nicht sichtbar.

Leser, die mit der anderen Bedeutung dieses Begriffs vertraut sind, möchten vielleicht lieber sagen, dass Objekte und Arrays als Wert übergeben werden, aber der übergebene Wert ist eigentlich eine Referenz und nicht das Objekt selbst.

13
igor

In JavaScript bestimmt der Typ des Werts ausschließlich , ob dieser Wert durch value-copy zugewiesen wird. oder durch Referenzkopie .

Primitive Werte werden immer von value-copy zugewiesen/übergeben :

  • null
  • undefined
  • zeichenfolge
  • nummer
  • boolescher Wert
  • symbol in ES6

Zusammengesetzte Werte werden immer per Referenzkopie zugewiesen/übergeben

  • objekte
  • arrays
  • funktion

Zum Beispiel

var a = 2;
var b = a; // `b` is always a copy of the value in `a`
b++;
a; // 2
b; // 3

var c = [1,2,3];
var d = c; // `d` is a reference to the shared `[1,2,3]` value
d.Push( 4 );
c; // [1,2,3,4]
d; // [1,2,3,4]

Da 2 im obigen Snippet ein skalares Grundelement ist, enthält a eine erste Kopie dieses Werts, und b wird eine andere Kopie des Werts zugewiesen. Wenn Sie b ändern, ändern Sie in keiner Weise den Wert in a.

Aber beide c und d sind separate Verweise auf denselben gemeinsamen Wert [1,2,3], der ein zusammengesetzter Wert ist. Es ist wichtig zu beachten, dass weder c noch d mehr den [1,2,3] -Wert "besitzt" - beide sind nur gleichwertige Verweise auf den Wert. Wenn Sie also eine der Verweise verwenden, um (.Push(4)) den tatsächlich gemeinsam genutzten array Wert selbst zu ändern, wirkt sich dies nur auf den einen gemeinsam genutzten Wert aus, und beide Verweise verweisen auf den neu geänderten Wert [1,2,3,4].

var a = [1,2,3];
var b = a;
a; // [1,2,3]
b; // [1,2,3]

// later
b = [4,5,6];
a; // [1,2,3]
b; // [4,5,6]

Wenn wir die Zuordnung b = [4,5,6] vornehmen, haben wir keinerlei Einfluss darauf, wo a noch referenziert ([1,2,3]). Um dies zu tun, müsste b ein Zeiger auf a sein und nicht ein Verweis auf array - aber es gibt keine solche Fähigkeit in JS!

function foo(x) {
    x.Push( 4 );
    x; // [1,2,3,4]

    // later
    x = [4,5,6];
    x.Push( 7 );
    x; // [4,5,6,7]
}

var a = [1,2,3];

foo( a );

a; // [1,2,3,4]  not  [4,5,6,7]

Wenn wir das Argument a übergeben, weist es a eine Kopie der Referenz auf x zu. x und a sind separate Referenzen, die auf denselben [1,2,3] -Wert verweisen. Jetzt können wir innerhalb der Funktion diese Referenz verwenden, um den Wert selbst zu mutieren (Push(4)). Wenn wir jedoch die Zuweisung x = [4,5,6] vornehmen, hat dies keinerlei Einfluss darauf, wohin die anfängliche Referenz a zeigt - sie zeigt immer noch auf den (jetzt geänderten) Wert [1,2,3,4].

Um einen zusammengesetzten Wert (wie array) effektiv als Wertkopie zu übergeben, müssen Sie manuell eine Kopie davon erstellen, damit die übergebene Referenz nicht immer noch auf das Original verweist. Zum Beispiel:

foo( a.slice() );

Zusammengesetzter Wert (Objekt, Array usw.), der als Referenzkopie übergeben werden kann

function foo(wrapper) {
    wrapper.a = 42;
}

var obj = {
    a: 2
};

foo( obj );

obj.a; // 42

Hier fungiert obj als Wrapper für die skalare Primitiveigenschaft a. Bei der Übergabe an foo(..) wird eine Kopie der Referenz obj übergeben und auf den Parameter wrapper gesetzt. Wir können jetzt die Referenz wrapper verwenden, um auf das gemeinsam genutzte Objekt zuzugreifen und seine Eigenschaft zu aktualisieren. Nach Beendigung der Funktion wird obj.a der aktualisierte Wert 42 angezeigt.

Quelle

12
zangw

JavaScript übergibt primitive Typen nach Wert und Objekttypen nach Referenz

Nun streiten sich die Leute endlos darüber, ob "Referenzübergabe" die richtige Art ist, um zu beschreiben, was Java et al. eigentlich tun. Der Punkt ist dieser:

  1. Beim Übergeben eines Objekts wird das Objekt nicht kopiert.
  2. Für ein an eine Funktion übergebenes Objekt können die Mitglieder von der Funktion geändert werden.
  3. Ein an eine Funktion übergebener Grundwert kann von der Funktion nicht geändert werden. Eine Kopie wird erstellt.

In meinem Buch wird das als Referenzübergabe bezeichnet.

- Brian Bi - Welche Programmiersprachen werden als Referenz übergeben?


Aktualisieren

Hier ist eine Gegenargumentation dazu:

In JavaScript ist keine Referenzübergabe verfügbar.

6
georgeawg

Dies ist kaum eine Erklärung für die Übergabe von Werten und Verweisen (JavaScript). In diesem Konzept geht es darum, die Variable als Referenz und die Variable als Referenz zu übergeben.

Übergabe nach Wert (primitiver Typ)

var a = 3;
var b = a;

console.log(a); // a = 3
console.log(b); // b = 3

a=4;
console.log(a); // a = 4
console.log(b); // b = 3
  • gilt für alle primitiven Typen in JavaScript (Zeichenfolge, Zahl, Boolescher Wert, undefinierter Wert und Nullwert).
  • a wird ein Speicher zugewiesen (z. B. 0x001) und b erstellt eine Kopie des Werts im Speicher (z. B. 0x002).
  • Das Ändern des Werts einer Variablen wirkt sich also nicht auf die andere aus, da sich beide an zwei verschiedenen Orten befinden.

Referenzübergabe (Objekte)

var c = { "name" : "john" };
var d = c;

console.log(c); // { "name" : "john" }
console.log(d); // { "name" : "john" }

c.name = "doe";

console.log(c); // { "name" : "doe" }
console.log(d); // { "name" : "doe" }
  • Die JavaScript-Engine weist das Objekt der Variablen c zu und verweist auf einen Speicher, z. B. (0x012).
  • Wenn d = c ist, zeigt d in diesem Schritt auf dieselbe Position (0x012).
  • Das Ändern des Werts eines Änderungswerts für beide Variablen.
  • Funktionen sind Objekte

Sonderfall, Referenz übergeben (Objekte)

c = {"name" : "jane"};
console.log(c); // { "name" : "jane" }
console.log(d); // { "name" : "doe" }
  • Der Gleichheitsoperator (=) richtet einen neuen Speicherplatz oder eine neue Adresse ein
5

teilen, was ich über Referenzen in JavaScript weiß

In JavaScript werden Objekte als Referenzen gespeichert:

var a = {
  a: 1,
  b: 2,
  c: 3
};
var b = a;

// b.c is referencing to a.c value
console.log(b.c) // Output: 3
// Changing value of b.c
b.c = 4
// Also changes the value of a.c
console.log(a.c) // Output: 4
4
student

Semantik!! Das Festlegen konkreter Definitionen führt zwangsläufig dazu, dass einige Antworten und Kommentare nicht kompatibel sind, da sie nicht dasselbe beschreiben, auch wenn dieselben Wörter und Ausdrücke verwendet werden. Es ist jedoch wichtig, die Verwirrung zu überwinden (insbesondere für neue Programmierer).

Erstens gibt es mehrere Abstraktionsebenen, die nicht jeder zu begreifen scheint. Neuere Programmierer, die in Sprachen der vierten oder fünften Generation gelernt haben, haben möglicherweise Schwierigkeiten, sich mit Konzepten zu befassen, die Assembly- oder C-Programmierern vertraut sind, die nicht durch Zeiger auf Zeiger auf Zeiger in Phasen unterteilt sind. Pass-by-Reference bedeutet nicht nur die Möglichkeit, ein referenziertes Objekt mithilfe einer Funktionsparametervariable zu ändern.

Variable: Kombiniertes Konzept eines Symbols, das auf einen Wert an einer bestimmten Stelle im Speicher verweist. Dieser Begriff ist in der Regel zu geladen, als dass er für die Erörterung von Details verwendet werden könnte.

Symbol: Textzeichenfolge, mit der auf eine Variable verwiesen wird (d. H. Name der Variablen).

Wert: Bestimmte Bits im Speicher gespeichert und mit dem Variablensymbol referenziert.

Speicherort: Wo der Wert einer Variablen gespeichert wird. (Der Ort selbst wird durch eine Zahl dargestellt, die vom am Ort gespeicherten Wert getrennt ist.)

Funktionsparameter: In einer Funktionsdefinition deklarierte Variable, die zur Referenzierung der an die Funktion übergebenen Variablen verwendet wird.

Funktionsargument: Variable außerhalb der Funktion, die vom Aufrufer an die Funktion übergeben wird.

Objektvariable: Variable, deren grundlegender Grundwert nicht das "Objekt" selbst ist, sondern deren Wert ein Zeiger (Speicherplatzwert) auf einen anderen Speicherplatz ist, an dem die tatsächlichen Daten des Objekts gespeichert sind. In den meisten Sprachen der höheren Generation wird der "Zeiger" -Aspekt durch die automatische Entreferenzierung in verschiedenen Kontexten effektiv ausgeblendet.

Primitive Variable: Variable, deren Wert IS der tatsächliche Wert ist. Selbst dieses Konzept kann durch Auto-Boxing und objektähnliche Kontexte verschiedener Sprachen kompliziert werden. Die allgemeine Idee ist jedoch, dass der Wert der Variablen IS der tatsächliche Wert ist, der durch das Symbol der Variablen dargestellt wird, und nicht ein Zeiger auf einen anderen Speicher Standort.

Funktionsargumente und Parameter sind nicht dasselbe. Der Wert einer Variablen ist auch nicht das Objekt der Variablen (wie bereits von verschiedenen Personen hervorgehoben, aber anscheinend ignoriert). Diese Unterscheidungen sind entscheidend für das richtige Verständnis.

Pass-by-Wert oder Call-by-Sharing (für Objekte): Der Wert des Funktionsarguments wird auf einen anderen Speicherort kopiert, auf den durch das Parametersymbol der Funktion verwiesen wird (unabhängig davon, ob es sich auf dem Stapel oder befindet) Haufen). Mit anderen Worten, der Funktionsparameter hat eine Kopie des Werts des übergebenen Arguments erhalten ... UND (kritisch) den Wert des Arguments IS NIEMALS von der aufrufenden Funktion AKTUALISIERT/GEÄNDERT/GEÄNDERT. Denken Sie daran, dass der Wert einer Objektvariablen NICHT das Objekt selbst ist, sondern der Zeiger auf das Objekt. Wenn Sie also eine Objektvariable als Wert übergeben, wird der Zeiger auf die Funktionsparametervariable kopiert. Der Wert des Funktionsparameters zeigt auf genau dasselbe Objekt im Speicher. Die Objektdaten selbst können direkt über den Funktionsparameter geändert werden, ABER der Wert des Funktionsarguments IS NIE AKTUALISIERT, sodass es weiterhin auf das gleiche zeigt Objekt während und auch nach dem Funktionsaufruf (auch wenn die Daten seines Objekts geändert wurden oder wenn dem Funktionsparameter insgesamt ein anderes Objekt zugewiesen wurde). Es ist falsch zu schließen, dass das Funktionsargument als Referenz übergeben wurde, nur weil das referenzierte Objekt über die Funktionsparametervariable aktualisiert werden kann.

Call/Pass-by-Reference: Der Wert des Funktionsarguments kann/wird direkt durch den entsprechenden Funktionsparameter aktualisiert. Wenn es hilft, wird der Funktionsparameter zu einem effektiven "Alias" für das Argument - sie verweisen effektiv auf denselben Wert am selben Speicherort. Wenn es sich bei einem Funktionsargument um eine Objektvariable handelt, unterscheidet sich die Möglichkeit zum Ändern der Objektdaten nicht vom Fall der Übergabe von Werten, da der Funktionsparameter weiterhin auf dasselbe Objekt wie das Argument verweist. Wenn im Fall der Objektvariablen der Funktionsparameter auf ein völlig anderes Objekt gesetzt ist, zeigt das Argument ebenfalls auf das andere Objekt - dies ist im Fall der Wertübergabe nicht der Fall.

JavaScript wird nicht als Referenz übergeben. Wenn Sie genau hinsehen, werden Sie feststellen, dass alle gegensätzlichen Meinungen falsch verstehen, was unter Wertübergabe zu verstehen ist, und fälschlicherweise den Schluss ziehen, dass die Fähigkeit, die Daten eines Objekts über den Funktionsparameter zu aktualisieren, synonym zu "Wertübergabe" ist.

Objekt klonen/kopieren: Ein neues Objekt wird erstellt und die Daten des ursprünglichen Objekts werden kopiert. Dies kann eine tiefe oder flache Kopie sein, der Punkt ist jedoch, dass ein neues Objekt erstellt wird. Das Erstellen einer Kopie eines Objekts unterscheidet sich von der Wertübergabe. Einige Sprachen unterscheiden zwischen Klassenobjekten und Strukturen (oder Ähnlichem) und haben möglicherweise ein anderes Verhalten beim Übergeben von Variablen der verschiedenen Typen. Bei der Übergabe von Objektvariablen führt JavaScript dies jedoch nicht automatisch durch. Das Fehlen des automatischen Klonens von Objekten führt jedoch nicht zu einer Referenzübergabe.

3
C Perkins

Das Übergeben von Argumenten an eine Funktion in JavaScript entspricht dem Übergeben von Parametern als Zeigerwert in C:

/*
The following C program demonstrates how arguments
to JavaScript functions are passed in a way analogous
to pass-by-pointer-value in C. The original JavaScript
test case by @Shog9 follows with the translation of
the code into C. This should make things clear to
those transitioning from C to JavaScript.

function changeStuff(num, obj1, obj2)
{
    num = num * 10;
    obj1.item = "changed";
    obj2 = {item: "changed"};
}

var num = 10;
var obj1 = {item: "unchanged"};
var obj2 = {item: "unchanged"};
changeStuff(num, obj1, obj2);
console.log(num);
console.log(obj1.item);    
console.log(obj2.item);

This produces the output:

10
changed
unchanged
*/

#include <stdio.h>
#include <stdlib.h>

struct obj {
    char *item;
};

void changeStuff(int *num, struct obj *obj1, struct obj *obj2)
{
    // make pointer point to a new memory location
    // holding the new integer value
    int *old_num = num;
    num = malloc(sizeof(int));
    *num = *old_num * 10;
    // make property of structure pointed to by pointer
    // point to the new value
    obj1->item = "changed";
    // make pointer point to a new memory location
    // holding the new structure value
    obj2 = malloc(sizeof(struct obj));
    obj2->item = "changed";
    free(num); // end of scope
    free(obj2); // end of scope
}

int num = 10;
struct obj obj1 = { "unchanged" };
struct obj obj2 = { "unchanged" };

int main()
{
    // pass pointers by value: the pointers
    // will be copied into the argument list
    // of the called function and the copied
    // pointers will point to the same values
    // as the original pointers
    changeStuff(&num, &obj1, &obj2);
    printf("%d\n", num);
    puts(obj1.item);
    puts(obj2.item);
    return 0;
}
3
John Sonderson

Mein einfacher Weg, dies zu verstehen ...

  • Beim Aufruf einer Funktion übergeben Sie den Inhalt (Referenz oder Wert) der Argumentvariablen, nicht die Variablen selbst.

    var var1 = 13;
    var var2 = { prop: 2 };
    
    //13 and var2's content (reference) are being passed here
    foo(var1, var2); 
    
  • Innerhalb der Funktion empfangen die Parametervariablen inVar1 und inVar2 den übergebenen Inhalt.

    function foo(inVar1, inVar2){
        //changing contents of inVar1 and inVar2 won't affect variables outside
        inVar1 = 20;
        inVar2 = { prop: 7 };
    }
    
  • Da inVar2 die Referenz von { prop: 2 } erhalten hat, können Sie den Wert der Objekteigenschaft ändern.

    function foo(inVar1, inVar2){
        inVar2.prop = 7; 
    }
    
2
dpp

Für Anwälte in Programmiersprachen habe ich die folgenden Abschnitte von ECMAScript 5.1 durchgesehen (das ist einfacher zu lesen als die neueste Ausgabe) und bin so weit gegangen, zu fragen es auf der ECMAScript-Mailingliste.

TL; DR: Alles wird als Wert übergeben, aber Eigenschaften von Objekten sind Referenzen, und die Definition von Objekt fehlt gruselig im Standard.

Konstruktion von Argumentlisten

In Abschnitt 11.2.4 "Argumentlisten" erfahren Sie Folgendes, wenn Sie eine Argumentliste mit nur einem Argument erstellen:

Die Produktionsargumentliste: AssignmentExpression wird wie folgt ausgewertet:

  1. Ref sei das Ergebnis der Auswertung von AssignmentExpression.
  2. Sei arg GetValue (ref).
  3. Gibt eine Liste zurück, deren einziger Eintrag arg ist.

In diesem Abschnitt werden auch Fälle aufgeführt, in denen die Argumentliste 0 oder> 1 Argumente enthält.

Somit wird alles als Referenz übergeben.

Zugriff auf Objekteigenschaften

Abschnitt 11.2.1 "Property Accessors"

Die Produktion MemberExpression: MemberExpression [Expression] wird wie folgt ausgewertet:

  1. Lassen Sie baseReference das Ergebnis der Auswertung von MemberExpression sein.
  2. Lassen Sie baseValue GetValue (baseReference) sein.
  3. Lassen Sie propertyNameReference das Ergebnis der Auswertung von Expression sein.
  4. Lassen Sie propertyNameValue GetValue (propertyNameReference) sein.
  5. Rufen Sie CheckObjectCoercible (baseValue) auf.
  6. Lassen Sie propertyNameString ToString (propertyNameValue) sein.
  7. Wenn die syntaktische Produktion, die ausgewertet wird, im Code für den strikten Modus enthalten ist, sei strikt wahr, andernfalls sei strikt falsch.
  8. Gibt einen Wert vom Typ Referenz zurück Deren Basiswert ist baseValue und der Name, auf den verwiesen wird, ist propertyNameString. Das Flag für den strengen Modus ist streng.

Somit stehen Eigenschaften von Objekten immer als Referenz zur Verfügung.

Zu Referenzzwecken

In Abschnitt 8.7 "Der Referenzspezifikationstyp" wird beschrieben, dass Referenzen keine reellen Typen in der Sprache sind - sie werden nur zur Beschreibung des Löschverhaltens, des Typs und der Zuweisungsoperatoren verwendet.

Definition von "Objekt"

In Version 5.1 ist definiert, dass "Ein Objekt eine Sammlung von Eigenschaften ist". Daher können wir schließen, dass der Wert des Objekts die Auflistung ist, aber was der Wert der Auflistung ist, ist in der Spezifikation schlecht definiert und erfordert ein wenig Aufwand zu verstehen.

2
DannyNiu

Es gibt einige Diskussionen über die Verwendung des Begriffs "Referenzübergabe" in JavaScript hier , aber um Ihre Frage zu beantworten:

Ein Objekt wird automatisch als Referenz übergeben, ohne dass es speziell angegeben werden muss

(Aus dem oben genannten Artikel.)

2
Jack Sleight

Wenn Sie in einer einfachen Sprache eine Variable als Referenz übergeben möchten, müssen Sie beim Erstellen der Funktion eine bestimmte Syntax verwenden:

int myAge = 14;
increaseAgeByRef(myAge);
function increaseAgeByRef(int &age) {
  *age = *age + 1;
}

Der &age ist eine Referenz auf myAge, aber wenn Sie den Wert möchten, müssen Sie die Referenz mit *age konvertieren.

Javascript ist eine Hochsprache, die diese Konvertierung für Sie durchführt. Obwohl Objekte als Referenz übergeben werden, konvertiert die Sprache den Referenzparameter in den Wert. Sie müssen & für die Funktionsdefinition nicht verwenden, um sie als Referenz zu übergeben, und * für den Funktionskörper nicht, um die Referenz in den Wert zu konvertieren. JS erledigt dies für Sie.

Wenn Sie versuchen, ein Objekt innerhalb einer Funktion zu ändern, indem Sie dessen Wert ersetzen (dh age = {value:5}), wird die Änderung nicht beibehalten, wenn Sie jedoch dessen Eigenschaften ändern (dh age.value = 5), wird dies auch durchgeführt .

Weitere Informationen

2
Narayon

Ich habe diese Antworten mehrmals gelesen, habe sie aber erst wirklich verstanden, als ich die technische Definition von "Call by sharing" , wie sie von Barbara Liskov genannt wird, kannte

Die Semantik von Call-by-Sharing unterscheidet sich von Call-by-Reference darin, dass Zuweisungen zu Funktionsargumenten innerhalb der Funktion für den Aufrufer nicht sichtbar sind (im Gegensatz zur Referenzsemantik) [Zitieren erforderlich], so dass z. Wenn eine Variable übergeben wurde, ist es nicht möglich, eine Zuweisung für diese Variable im Gültigkeitsbereich des Aufrufers zu simulieren. Da die Funktion jedoch Zugriff auf dasselbe Objekt wie der Aufrufer hat (es wird keine Kopie erstellt), sind für den Aufrufer Mutationen an diesen Objekten innerhalb der Funktion sichtbar, sofern die Objekte veränderbar sind Semantik. Mutationen eines veränderlichen Objekts innerhalb der Funktion sind für den Aufrufer sichtbar, da das Objekt nicht kopiert oder geklont wird - es wird gemeinsam genutzt.

Das heißt, Parameterreferenzen können geändert werden, wenn Sie auf den Parameterwert selbst zugreifen. Andererseits verschwindet die Zuweisung zu einem Parameter nach der Auswertung und ist für den Funktionsaufrufer nicht zugänglich.

1
steviejay

Die MDN-Dokumente erklären es klar, ohne zu wortreich zu sein:

Die Parameter eines Funktionsaufrufs sind die Argumente der Funktion . Argumente werden an Funktionen als Wert übergeben. Wenn die Funktion den Wert eines Arguments ändert, wird diese Änderung nicht global oder in der aufrufenden Funktion wiedergegeben. Objektreferenzen sind jedoch auch Werte, und sie sind speziell: Wenn die Funktion die Eigenschaften des referenzierten Objekts ändert, ist diese Änderung außerhalb der Funktion sichtbar, (...)

Quelle: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Description

1
miguelr

Die prägnanteste Erklärung, die ich gefunden habe, war AirBNB-Styleguide :

  • Primitive : Wenn Sie auf einen primitiven Typ zugreifen, arbeiten Sie direkt an dessen Wert

    • zeichenfolge
    • nummer
    • boolescher Wert
    • null
    • undefined

Z.B.:

var foo = 1,
    bar = foo;

bar = 9;

console.log(foo, bar); // => 1, 9
  • Komplex : Wenn Sie auf einen komplexen Typ zugreifen, bearbeiten Sie eine Referenz auf seinen Wert

    • objekt
    • array
    • funktion

Z.B.:

var foo = [1, 2],
    bar = foo;

bar[0] = 9;

console.log(foo[0], bar[0]); // => 9, 9

Das heißt Effektiv werden primitive Typen als Wert und komplexe Typen als Referenz übergeben.

1
lid

Eine einfache Methode, um festzustellen, ob ein Objekt als Referenz übergeben wurde, besteht darin, eine Swap-Funktion zu schreiben. In C können Sie beispielsweise Folgendes ausführen:

void swap(int *i, int *j)
{
    int t;
    t = *i;
    *i = *j;
    *j = t;
}

Wenn Sie dies in JavaScript nicht tun können, ist es nicht "Referenzübergabe".

0
Ross

Ich habe die extend-Methode der nderscore.js-Bibliothek als sehr nützlich empfunden, wenn ich ein Objekt als Parameter übergeben möchte, der entweder geändert oder vollständig ersetzt werden kann.

function replaceOrModify(aObj) {
  if (modify) {

    aObj.setNewValue('foo');

  } else {

   var newObj = new MyObject();
   // _.extend(destination, *sources) 
   _.extend(newObj, aObj);
  }
}
0
Jack
  1. Primitive (Zahl, Boolescher Wert usw.) werden als Wert übergeben.
    • Saiten sind unveränderlich, also ist es für sie eigentlich egal.
  2. Objekte werden als Referenz übergeben (die Referenz wird als Wert übergeben).
0
uriz

Ich würde sagen, es ist Pass-by-Kopie -

Berücksichtigen Sie, dass Argumente und Variablenobjekte Objekte sind, die während des Ausführungskontexts erstellt wurden, der zu Beginn des Funktionsaufrufs erstellt wurde - und Ihr tatsächlicher Wert/Ihre tatsächliche Referenz, die an die Funktion übergeben wurde, wird nur in diesen Argumenten + Variablenobjekten gespeichert.

Einfach ausgedrückt werden bei primitiven Typen die Werte zu Beginn des Funktionsaufrufs kopiert, bei Objekttypen wird die Referenz kopiert.

0
lyslim