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


Die primitiven Typen (Number, String usw.) werden als Wert übergeben, aber Objekte sind unbekannt, da sie beide als Wert übergeben werden können (falls wir berücksichtigen, dass eine Variable, die ein Objekt enthält, tatsächlich eine Referenz auf das Objekt ist ) und als Verweis übergeben (wenn wir berücksichtigen, dass die Variable für das Objekt das Objekt selbst enthält).

Obwohl es am Ende nicht wirklich wichtig ist, möchte ich wissen, wie man die Argumente, die die Konventionen passieren, korrekt darstellt. Gibt es einen Auszug aus der JavaScript-Spezifikation, der definiert, was die Semantik dazu sein soll?


1137
2018-02-05 21:23


Ursprung


Antworten:


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 es reiner Wert war, dann ändere obj1.item hätte keine Auswirkungen auf die obj1 außerhalb der Funktion.
  • Wenn es rein durch Verweis gegangen wäre, hätte sich alles verändert. num wäre 100, und obj2.item würde lesen "changed".

Stattdessen wird der übergebene Artikel als Wert übergeben. Aber das Element, das von 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), die sich nicht auf den Artikel auswirken, der in den Parameter eingegeben wurde. Aber wenn du das änderst INTERN des Parameters, der sich wieder ausbreitet (wie bei obj1).


1359
2018-03-15 16:38



Es wird immer nach Wert übergeben, aber bei Objekten ist der Wert der Variablen eine Referenz. Aus diesem Grund, wenn Sie ein Objekt übergeben und ändern Mitglieder, diese Änderungen bleiben außerhalb der Funktion bestehen. Das macht es aussehen wie Pass als Referenz. Aber wenn Sie den Wert der Objektvariable tatsächlich ändern, werden Sie sehen, dass die Änderung nicht fortbesteht, was beweist, dass sie wirklich Wert ist.

Beispiel:

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

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

var x = {member:"foo"};

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

alert("before changeMember: " + x.member);
changeMember(x);
alert("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

376
2018-02-05 21:37



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

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


132
2017-08-04 11:06



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

Es ist an der Zeit, alles, was Sie über Wert / Referenz wissen, zu verwerfen.

Denn in JavaScript spielt es keine Rolle, ob es nach Wert oder Verweis oder was auch immer weitergegeben wird. Was zählt, ist die Mutation gegen die Zuweisung der Parameter, die an eine Funktion übergeben werden.

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

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

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

Nun, sagen wir, dass wir Objekt1 besser mögen ... Also "zuweisen" wir eine neue Variable.

var favoriteObject = object1;

Als nächstes, aus welchem ​​Grund auch immer, entscheiden wir, dass wir Objekt 2 besser mögen. Also machen wir einfach eine kleine Neuzuweisung.

favoriteObject = object2;

Nichts ist mit object1 oder object2 passiert. Wir haben überhaupt keine Daten geändert. Alles, was wir taten, wurde neu zugewiesen, was unser Lieblingsobjekt ist. Es ist wichtig zu wissen, dass object2 und favoriteObject beide 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, nun schauen wir uns Primitive wie Strings an

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

Auch hier wählen wir einen Favoriten aus.

var favoriteString = string1;

Sowohl unsere Variablen favouriteString als auch string1 sind "Hello world" zugeordnet. Was nun, 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 Strings unveränderlich sind und wir es nicht mutiert haben. Alles, was wir getan haben, war "RE ASSIGN" favoriteString zu einer neuen Zeichenfolge. Dies hat es im Wesentlichen von String1 getrennt. Im vorherigen Beispiel, als wir unser Objekt umbenannt haben, haben wir nichts zugewiesen. (Nun, eigentlich ... wir haben die name -Eigenschaft einer neuen Zeichenfolge zugewiesen.) Stattdessen mutierten wir einfach das Objekt, das die Verbindungen zwischen den 2 Variablen und den zugrunde liegenden Objekten aufrechterhält.

Nun zu den Funktionen und Parametern ... Wenn Sie eine Funktion aufrufen und einen Parameter übergeben, tun Sie im Wesentlichen "Zuweisung" an eine neue Variable, und sie funktioniert genau so, als ob Sie sie einfach mit der Funktion zugewiesen hätten Gleiches (=) Zeichen.

Nimm 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, lassen Sie uns nun ein paar Beispiele mit Objekten geben ... 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
otherObj = {
    firstName: 'Jack',
    lastName: 'Frost'
};

// Now, otherObj and myObject are assigned to 2 very different objects
// And mutating one object no longer mutates 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 no longer mutates 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 gelesen haben, haben Sie vielleicht ein besseres Verständnis dafür, wie Funktionsaufrufe in Javascript funktionieren. Es spielt keine Rolle, ob etwas durch Referenz oder durch Wert weitergegeben wird ... Was wichtig ist, ist Zuordnung vs Mutation.

Jedes Mal, wenn Sie eine Variable an eine Funktion übergeben, werden Sie dem Namen der Parametervariablen "zugewiesen", genau wie wenn Sie das Gleichheitszeichen (=) verwendet hätten.

Denken Sie immer daran, dass das Gleichheitszeichen (=) die Zuweisung bedeutet. Denken Sie immer daran, dass das Übergeben eines Parameters an eine Funktion auch eine Zuweisung bedeutet. Sie sind gleich und die 2 Variablen sind auf die gleiche Weise verbunden.

Der einzige Zeitpunkt, zu dem das Ändern einer Variablen eine andere Variable beeinflusst, ist, wenn das zugrunde liegende Objekt mutiert ist.

Es macht keinen Sinn, zwischen Objekten und Primitiven zu unterscheiden, weil es genau so funktioniert, als ob Sie keine Funktion hätten und einfach das Gleichheitszeichen verwenden würden, um es einer neuen Variablen zuzuordnen.

Der einzige Fehler besteht darin, dass der Name der Variablen, die Sie an die Funktion übergeben, mit dem Namen des Funktionsparameters übereinstimmt. Wenn dies passiert, müssen Sie den Parameter innerhalb der Funktion so behandeln, als ob es eine ganz neue Variable wäre, die für die Funktion privat ist (weil es)

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'

84
2017-09-26 04:06



Folgendes berücksichtigen:

  1. Variablen sind Zeigerzu Werten im Speicher.
  2. Beim Neuzuweisen einer Variablen wird dieser Zeiger nur auf einen neuen Wert gesetzt.
  3. Das erneute Zuweisen einer Variablen wirkt sich niemals auf andere Variablen aus, die auf dasselbe Objekt zeigen

Damit, vergessen "nach Bezug / Wert" hänge nicht auf "pass by reference / value" auf, weil:

  1. Die Begriffe werden nur zur Beschreibung der Verhalten einer Sprache, nicht unbedingt die eigentliche zugrunde liegende Implementierung. Als Ergebnis dieser Abstraktion gehen kritische Details verloren, die für eine anständige Erklärung wesentlich sind, was unweigerlich zu der gegenwärtigen Situation führt, in der ein einzelner Begriff das tatsächliche Verhalten nicht adäquat beschreibt und ergänzende Informationen bereitgestellt werden müssen
  2. Diese Konzepte wurden ursprünglich nicht mit der Absicht definiert, insbesondere Javascript zu beschreiben, und daher fühle ich mich nicht gezwungen, sie zu verwenden, wenn sie nur zur Verwirrung beitragen.

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 Kommentare:

  • Es ist verlockend, das zu denken Primitive werden durch spezielle Regeln während erzwungen Objekte sind nicht, aber Primitive sind einfach das Ende der Zeigerkette.
  • Betrachten wir als letztes Beispiel, warum ein üblicher 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

57
2018-06-02 23:04



Objekt außerhalb einer Funktion wird in eine Funktion übergeben, indem ein Verweis auf das äußere Objekt gegeben wird. Wenn Sie diesen Verweis verwenden, um sein Objekt zu manipulieren, ist das Objekt außerhalb betroffen. Wenn Sie innerhalb der Funktion jedoch entschieden haben, den Verweis auf etwas anderes zu richten, haben Sie das Objekt überhaupt nicht beeinflusst, weil Sie lediglich den Verweis auf etwas anderes umgeleitet haben.


23
2018-02-13 11:00



Stellen Sie es sich so vor: Es ist immer an Wert vorbei. Der Wert eines Objekts ist jedoch nicht das Objekt selbst, sondern ein Verweis auf dieses Objekt.

Hier ist ein Beispiel, übergibt eine Nummer (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

Dies mit einem Objekt zu wiederholen, führt zu unterschiedlichen Ergebnissen:

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}

16
2018-02-05 21:49



Javascript ist immer pass-by-valueAlles ist vom Werttyp. Objekte sind Werte, Mitgliederfunktionen von Objekten sind selbst Werte (denken Sie daran, dass Funktionen in Javascript erstklassige Objekte sind). Auch bezüglich des Konzepts, dass alles in Javascript ein ist Objekt, das ist falsch. Strings, Symbole, Zahlen, Booleans, Nullen und undefined sind Primitive. Gelegentlich können sie einige Mitgliedsfunktionen und Eigenschaften nutzen, die von ihren Basisprototypen geerbt wurden, aber dies dient nur der Bequemlichkeit, es 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 Warnungen finden Sie den Wert als undefiniert.


14
2017-12-30 02:20



In JavaScript der Typ des Werts einzig und allein steuert, ob dieser Wert von zugewiesen wird Wertkopie oder von Referenzkopie.

Primitive Werte werden immer von Wertkopie zugewiesen / übergeben:

  • null
  • undefined
  • Zeichenfolge
  • Nummer
  • boolesch
  • Symbol in ES6

Zusammengesetzte Werte werden immer durch Referenzkopie zugewiesen / übergeben

  • Objekte
  • Arrays
  • Funktion

Beispielsweise

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]

Im obigen Ausschnitt, weil 2 ist ein Skalar-Primitiv, a hält eine erste Kopie dieses Wertes, und b wird eine andere Kopie des Wertes zugewiesen. Beim Wechsel b, Sie verändern den Wert in keiner Weise a.

Aber beide c und d sind separate Referenzen auf denselben gemeinsamen Wert [1,2,3], was ein zusammengesetzter Wert ist. Es ist wichtig, dies auch nicht zu beachten c Noch d mehr "besitzt" die [1,2,3] Wert - beide sind nur gleiche Peer-Referenzen auf den Wert. Also, wenn Sie entweder Referenz zu ändern (.push(4)) das tatsächlich geteilte array Wert selbst, wirkt sich nur auf den einen gemeinsamen Wert aus, und beide Referenzen 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 Aufgabe machen b = [4,5,6]Wir tun absolut nichts, um wo zu beeinflussen a referenziert immer noch ([1,2,3]). Das zu tun, b müsste ein Zeiger auf sein a anstatt eine Bezugnahme auf die array - aber keine solche Fähigkeit existiert 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 weitergeben a, es weist eine Kopie der a Bezug auf x. x und a sind separate Referenzen, die auf dasselbe verweisen [1,2,3] Wert. Nun können wir innerhalb der Funktion diese Referenz verwenden, um den Wert selbst zu mutieren (push(4)). Aber wenn wir den Auftrag machen x = [4,5,6]Dies wirkt sich in keiner Weise auf die anfängliche Referenz aus a zeigt - weist immer noch auf das (jetzt geänderte) [1,2,3,4] Wert.

Um einen zusammengesetzten Wert (wie ein array) Nach Wertkopie müssen Sie manuell eine Kopie davon erstellen, damit die übergebene Referenz nicht immer auf das Original verweist. Beispielsweise:

foo( a.slice() );

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

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

var obj = {
    a: 2
};

foo( obj );

obj.a; // 42

Hier, obj fungiert als Wrapper für die skalare primitive Eigenschaft a. Wenn übergeben an foo(..), eine Kopie von obj Referenz wird übergeben und auf die eingestellt wrapperParameter. Wir können jetzt das verwenden wrapper Verweis auf das freigegebene Objekt zugreifen und seine Eigenschaft aktualisieren. Nachdem die Funktion beendet ist, obj.a wird den aktualisierten Wert sehen 42.

Quelle


12
2018-05-12 22:20



Eine sehr detaillierte Erklärung über das Kopieren, Übergeben und Vergleichen nach Wert und Verweis ist in dieses Kapitel von "JavaScript: The Definitive Guide" Buch.

Bevor wir das Thema verlassen   Manipulieren von Objekten und Arrays durch   Hinweis, wir müssen einen Punkt klären   der Nomenklatur. Der Satz "pass vorbei   Referenz "kann mehrere Bedeutungen haben.   Auf einige Leser bezieht sich der Ausdruck auf   eine Funktionsaufruftechnik, die   Ermöglicht einer Funktion, neue Werte zuzuweisen   zu seinen Argumenten und diese zu haben   modifizierte Werte sichtbar außerhalb der   Funktion. Dies ist nicht der Begriff   wird in diesem Buch verwendet. Hier meinen wir   einfach, dass ein Verweis auf ein Objekt   oder Array - nicht das Objekt selbst -   wird an eine Funktion übergeben. Eine Funktion   kann die Referenz zum Ändern verwenden   Eigenschaften des Objekts oder der Elemente   des Arrays. Aber wenn die Funktion   überschreibt die Referenz mit a   Referenz auf ein neues Objekt oder Array   Diese Änderung ist nicht sichtbar   außerhalb der Funktion. Leser   vertraut mit der anderen Bedeutung von   dieser Begriff mag es vorziehen, das zu sagen   Objekte und Arrays werden übergeben   Wert, aber der Wert, der übergeben wird, ist   eigentlich eher eine Referenz als die   Objekt selbst.

Eine Sache kann ich immer noch nicht herausfinden. Überprüfen Sie den Code unten. Irgendwelche Gedanken?

function A() {}
A.prototype.foo = function() {
    return 'initial value';
}


function B() {}
B.prototype.bar = A.prototype.foo;

console.log(A.prototype.foo()); //initial value
console.log(B.prototype.bar()); //initial value

A.prototype.foo = function() {
    return 'changed now';
}

console.log(A.prototype.foo()); //changed now
console.log(B.prototype.bar()); //Why still 'initial value'???

10
2018-02-05 21:36