Meine Meinung... Das ist die Art und Weise, wie ich es verstehe. (Sie können mich gerne korrigieren, wenn ich falsch liege)
Es ist an der Zeit, alles, was Sie über Wertübergabe / Referenz wissen, über Bord zu werfen.
Denn in JavaScript spielt es keine Rolle, ob es als Wert oder als Referenz oder wie auch immer übergeben wird. Worauf es ankommt, ist die Mutation bzw. Zuweisung der an eine Funktion übergebenen Parameter.
Okay, ich werde mein Bestes tun, 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 2 getrennte leere Objekte den Variablen "object1" und "object2" zugewiesen.
Nehmen wir nun an, dass uns Objekt1 besser gefällt... Also "weisen" wir eine neue Variable zu.
var favoriteObject = object1;
Dann entscheiden wir, aus welchen Gründen auch immer, dass uns Objekt 2 besser gefällt. Also nehmen wir eine kleine Neuzuweisung vor.
favoriteObject = object2;
Weder mit Objekt1 noch mit Objekt2 ist etwas passiert. Wir haben überhaupt keine Daten geändert. Wir haben lediglich 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 der beiden Variablen ändern.
object2.name = 'Fred';
console.log(favoriteObject.name) // Logs Fred
favoriteObject.name = 'Joe';
console.log(object2.name); // Logs Joe
OK, schauen wir uns nun Primitive wie z.B. Strings an
var string1 = 'Hello world';
var string2 = 'Goodbye world';
Wieder wählen wir einen Favoriten.
var favoriteString = string1;
Die Variablen favoriteString und string1 sind beide der Variable "Hello world" zugeordnet. Was passiert nun, wenn wir unseren favoriteString ändern wollen? Was wird dann passieren?
favoriteString = 'Hello everyone';
console.log(favoriteString); // Logs 'Hello everyone'
console.log(string1); // Logs 'Hello world'
Uh oh.... Was ist passiert? Wir konnten string1 nicht ändern, indem wir favoriteString geändert haben... Warum nur? Weil wir nicht ändern unser String Objekt . Alles, was wir getan haben, war, den Favoritenring neu zuzuweisen. variabel zu einer neuen Zeichenkette. Damit wurde sie im Wesentlichen von string1 getrennt. Im vorherigen Beispiel haben wir unser Objekt umbenannt, ohne ihm etwas zuzuweisen. (Nun, nicht dem Variable selbst ... wir haben jedoch die Eigenschaft name einem neuen String zugewiesen). Stattdessen haben wir das Objekt mutiert, das die Verbindungen zwischen den beiden Variablen und den zugrunde liegenden Objekten aufrechterhält. (Selbst wenn wir das Objekt ändern wollten oder mutieren das String-Objekt selbst nicht möglich, da Strings in JavaScript eigentlich unveränderlich sind).
Nun zu den Funktionen und der Übergabe von Parametern.... Wenn Sie eine Funktion aufrufen und einen Parameter übergeben, handelt es sich im Wesentlichen um eine "Zuweisung" an eine neue Variable, die genauso funktioniert, wie wenn Sie sie mit dem Gleichheitszeichen (=) zuweisen.
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 ein paar Beispiele mit Objekten stattdessen... 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 Beitrag ganz durchgelesen haben, verstehen Sie jetzt vielleicht besser, wie Funktionsaufrufe in JavaScript funktionieren. Es spielt keine Rolle, ob etwas als Referenz oder als Wert übergeben wird... Was zählt, ist Zuweisung vs. Mutation.
Jedes Mal, wenn Sie eine Variable an eine Funktion übergeben, weisen Sie ihr den Namen der Parametervariablen zu, genau wie bei der Verwendung des Gleichheitszeichens (=).
Denken Sie immer daran, dass das Gleichheitszeichen (=) eine Zuordnung bedeutet. Denken Sie immer daran, dass die Übergabe eines Parameters an eine Funktion in JavaScript bedeutet auch Zuweisung. Sie sind dasselbe, und die beiden Variablen sind auf genau dieselbe Weise miteinander verbunden (das heißt, sie sind es nicht, es sei denn, man zählt, dass sie demselben Objekt zugewiesen sind).
Das einzige Mal, dass sich die "Änderung einer Variablen" auf eine andere Variable auswirkt, ist, wenn das zugrunde liegende Objekt geändert wird (in diesem Fall haben Sie nicht die Variable, sondern das Objekt selbst geändert).
Es macht keinen Sinn, zwischen Objekten und Primitiven zu unterscheiden, denn es funktioniert genau so, als ob Sie keine Funktion hätten und nur das Gleichheitszeichen für die Zuweisung an eine neue Variable verwenden würden.
Das einzige Problem besteht darin, dass 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 innerhalb der Funktion so behandeln, als ob es sich um eine ganz neue, der Funktion vorbehaltene Variable handelt (denn das ist sie auch)
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'
0 Stimmen
Ich denke, wir haben genügend Beweise dafür, was die genaue Semantik der Sprache ist. Jetzt fehlt nur noch der Auszug aus der EcmaScript-Spezifikation, der sie definiert, und wir werden eine Antwort auf diese Frage haben.
8 Stimmen
Ich glaube, Sie haben versehentlich Ihre Definitionen von "passed-by-value" und "passed-by-reference" vertauscht... "passed-by-value (wenn wir davon ausgehen, dass eine Variable, die ein Objekt enthält, in Wirklichkeit ein Verweis auf das Objekt ist) und passed-by-reference (wenn wir davon ausgehen, dass die Variable auf das Objekt das Objekt selbst enthält)"
11 Stimmen
Ja. Unabhängig von der Syntax bedeutet "pass-by-reference" bei einem Funktionsaufruf in einer beliebigen Programmiersprache, dass die mit der übergebenen Variablen verbundenen Daten bei der Übergabe an die Funktion nicht kopiert werden und somit alle von der Funktion an der übergebenen Variablen vorgenommenen Änderungen nach Beendigung des Funktionsaufrufs im Programm erhalten bleiben. Pass-by-Value bedeutet, dass die mit der Variablen verbundenen Daten bei der Übergabe an die Funktion tatsächlich kopiert werden und dass alle von der Funktion an der Variablen vorgenommenen Änderungen verloren gehen, wenn die Variable bei der Rückkehr der Funktion aus dem Anwendungsbereich des Funktionskörpers verschwindet.
0 Stimmen
Wenn eine Funktion eine Variable zurückgibt, ist der zurückgegebene Wert dann ein Verweis auf die Variable im Funktionskörper oder eine Kopie der Variable im Funktionskörper?
0 Stimmen
@JohnSonderson, ich glaube, dass der Geltungsbereich der zurückgegebenen Variablen standardmäßig derselbe ist wie der der Funktion, die die Variable zurückgibt (Sie können dies testen, indem Sie eine Funktion als Variable definieren und diese zurückgeben). Das führt mich zu der Annahme, dass der zurückgegebene Wert genauso behandelt wird wie die Übergabe eines Arguments an eine Funktion - es wird der Wert kopiert (pass by value), aber wenn sich der Wert auf ein Objekt bezieht, wird die Referenz auf dieses Objekt kopiert, nicht das Objekt selbst. WEITER: AFAIK,
object.create
ist der einzige Mechanismus, der ein Objekt in Javascript klont (siehe stackoverflow.com/q/728360/2155068 ).1 Stimmen
@MjrKusanagi Ich glaube nicht.
Object.create
kann als richtige Klontechnik betrachtet werden, d. h. wenn Sie die Originalkopie des Objekts ändern, wirkt sich dies auf den Klon aus, nur Änderungen am Klon wirken sich nicht auf das Originalobjekt aus. Natürlich hat es seinen Nutzen und JavaScript wurde um dieses Konzept herum entwickelt (prototypische Vererbung), aber ich denke, es ist irreführend, wenn manObject.create
der einzige Mechanismus zum Klonen eines Objekts.9 Stimmen
Diese alte Frage ist etwas giftig, weil die Antwort, für die viele Stimmen abgegeben wurden, falsch ist. JavaScript ist streng Pass-by-Value .
2 Stimmen
@Pointy Ich kann nicht erkennen, wie das in der Antwort beschriebene Verhalten von JavaScript falsch sein soll. Ich stimme jedoch zu, dass sie nicht viel beiträgt - sie wiederholt nur die Frage. In der Antwort, die Sie verlinkt haben, heißt es, dass JavaScript strikt pass-by-value ist. Sie basiert jedoch auf einer Interpretation, wie es funktioniert. Den gleichen Fehler macht der Blogbeitrag. Es gibt immer noch keinen Auszug aus der Spezifikation, der die eine oder die andere Interpretation unterstützt (pass-by-value für alles und Objektvariablen sind Referenzen oder pass-by-value für Primitive und pass-by-reference für Objekte).
9 Stimmen
@DanailNachev Die Terminologie ist bedauerlicherweise verwirrend. Die Sache ist die, dass "Wertübergabe" und "Referenzübergabe" Begriffe sind, die aus der Zeit vor vielen moderneren Programmiersprachen stammen. Die Wörter "Wert" und "Referenz" beziehen sich auf speziell auf den Parameter, wie er im Ausdruck des Funktionsaufrufs erscheint. JavaScript wertet immer jeden Ausdruck in einer Funktionsaufruf-Parameterliste aus vor Aufruf der Funktion, so dass die Parameter immer Werte sind. Das Verwirrende daran ist, dass Verweise auf Objekte übliche JavaScript-Werte sind. Das macht es aber nicht zu einer "pass by reference"-Sprache.
4 Stimmen
@DanailNachev "pass by reference" bedeutet konkret, dass man, wenn man
var x=3, y=x; f(x); alert(y === x);
dann Funktionf()
kann den Warnbericht erstellenfalse
und nichttrue
. In JavaScript ist das nicht möglich, also ist es nicht pass-by-reference. Es ist gut, dass es möglich ist, Referenzen auf veränderbare Objekte zu übergeben, aber das ist nicht das, was "pass by reference" bedeutet. Wie ich schon sagte, ist es schade, dass die Terminologie so verwirrend ist.1 Stimmen
@Pointy, ich glaube nicht, dass ich mit dem, was Sie sagen, nicht einverstanden bin. Aber ich denke, Sie sollten trotzdem die Call-by-Sharing Wikipedia-Link, der in dem Beitrag, über den Sie sich beschweren, genannt wird.
0 Stimmen
@DanailNachev Ich habe kein Problem mit dieser Terminologie ("Call-by-Sharing"), und es ist offensichtlich richtig, dass die Leute einen solchen Begriff wirklich wollen. Wie im Artikel erwähnt, ist er jedoch nicht gebräuchlich. Danke für den Hinweis!
0 Stimmen
Number und String sind keine Primitive. Sie sind Wrapper-Objekte, die eine Zahl oder einen String (Kleinbuchstaben) umhüllen, die Primitive sind.
1 Stimmen
Dies ist einer der vielen Gründe, warum JavaScript schlecht ist. In anderen Sprachen wie C und sogar PHP kann man die Argumentübergabe IMPLICITLY per Wert oder per Referenz festlegen. In JS ist es ein semantisches Durcheinander. Ich kann es kaum erwarten, dass WebAssembly zum Mainstream wird und den ersten Nagel in den Sarg von JS schlägt.
0 Stimmen
@RyanNerd: Sie können nicht in C. C ist immer pass-by-value. PHP hat callee-side pass-by-reference, ja, und es ist schrecklich. C# ist ein Beispiel für eine Sprache, die es richtig macht, indem sie explizite
ref
und eine Unterscheidung fürout
.1 Stimmen
@RyanNerd - Du liegst völlig falsch. JavaScript ist kein semantisches Chaos. In diesem Fall ist es geradlinig und konsistent: JavaScript ist "pass by value". Das war's. Mehr muss nicht gesagt werden. Dieses Verhalten wird jedem, der Java, C# oder PHP verwendet hat, völlig vertraut sein.
0 Stimmen
Sonderfall: Beibehaltung von Referenzen von Werten als Teil anderer Variablenbindungen. Betrachten Sie
const a = 1, b = a + 2, c = [ a, 2 ]; a = 4;
. Jetzt,b
ist noch3
, nicht6
;c
es[ 1, 2 ]
, nicht[ 4, 2 ]
. Es gibt keine inhärente Verbindung zwischena
und die anderen Variablen; die Tatsache, dass die eine als Teil der Definition der anderen verwendet wird, ist irrelevant. Nach der Lektüre dieser Q&A sollte es jedoch keine Überraschung sein, dass inconst a = { x: 1 }, b = [ a, { x: 2 } ]; a.x = 4
,b
es[ { x: 4 }, { x: 2 } ]
. Siehe Variablenwert ändern, der Teil der Definition einer anderen Variablen ist .