1753 Stimmen

Ist JavaScript eine pass-by-reference oder pass-by-value Sprache?

Die primitiven Typen (Zahl, Zeichenkette usw.) werden als Wert übergeben, aber Objekte sind unbekannt, da sie sowohl als Wert (wenn wir davon ausgehen, dass eine Variable, die ein Objekt enthält, in Wirklichkeit ein Verweis auf das Objekt ist) als auch als Verweis (wenn wir davon ausgehen, dass die Variable auf das Objekt das Objekt selbst enthält) übergeben werden können.

Auch wenn es am Ende keine Rolle spielt, möchte ich wissen, wie man die Argumente richtig darstellt, indem man die Konventionen übergeht. Gibt es einen Auszug aus JavaScript-Spezifikation, die definiert, was sollte die Semantik in Bezug auf diese sein?

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.

28voto

user779764 Punkte 294

Ein Objekt außerhalb einer Funktion wird an eine Funktion übergeben, indem ein Verweis auf das Objekt außerhalb gegeben wird.

Wenn Sie diese Referenz verwenden, um ihr Objekt zu manipulieren, ist das Objekt außerhalb davon betroffen. Wenn Sie jedoch innerhalb der Funktion beschließen, den Verweis auf etwas anderes zu richten, wirkt sich dies überhaupt nicht auf das äußere Objekt aus, da Sie lediglich den Verweis auf etwas anderes gerichtet haben.

27voto

igor Punkte 4913

Eine sehr ausführliche Erklärung zum Kopieren, Übergeben und Vergleichen von Werten und Referenzen findet sich in dieses Kapitel der "JavaScript: Der endgültige Leitfaden" Buch.

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

Der Ausdruck "Verweisungsübergang Referenz" kann mehrere Bedeutungen haben. Für einige Leser bezieht sich der Ausdruck auf eine Technik des Funktionsaufrufs, die einer Funktion erlaubt, ihren Argumenten neue Werte zuzuweisen ihren Argumenten neue Werte zuzuweisen und diese geänderten Werte außerhalb der Funktion. Dies ist nicht die Art und Weise, wie der Begriff in diesem Buch verwendet wird.

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

Leserinnen und Leser die mit der anderen Bedeutung des dieses Begriffs vertraut sind, ziehen es vielleicht vor, zu sagen, dass Objekte und Arrays werden durch Wert übergeben werden, aber der Wert, der übergeben wird, ist eigentlich ein Verweis und nicht das Objekt selbst.

0 Stimmen

Wow, das ist ja unglaublich verwirrend. Wer, der bei klarem Verstand ist, würde einen gut etablierten Begriff so definieren, dass er die genaues Gegenteil und sie dann auf diese Weise verwenden? Kein Wunder, dass so viele Antworten hier auf diese Frage so verwirrend sind.

0 Stimmen

Diese Antwort ist der Schlüssel zum Verständnis dessen, was andere Menschen zu diesem Thema schreiben. Die meisten Menschen wissen nicht, dass es zwei Definitionen des Begriffs "pass by reference" gibt, so dass man beim Lesen der Erklärung eine fundierte Vermutung anstellen muss, welche Bedeutung des Begriffs sie verwenden. Das Buchkapitel, auf das in dieser Antwort verwiesen wird, ist ebenfalls nützlich für ein tieferes Verständnis des Themas.

27voto

Phil Mander Punkte 1699

Stellen Sie sich das folgendermaßen vor: Es ist immer eine Übergabe nach Wert. Der Wert eines Objekts ist jedoch nicht das Objekt selbst, sondern ein Verweis auf dieses Objekt.

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

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

Wiederholt man dies mit einem Objekt, erhält man andere 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}

22voto

Michael Roberts Punkte 377

JavaScript ist immer Pass-by-Value ; alles ist vom Typ Wert.

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

Gelegentlich können sie einige Mitgliedsfunktionen und Eigenschaften nutzen, die sie von ihren Basisprototypen geerbt haben, aber das ist nur der Einfachheit halber. Das bedeutet nicht, dass sie selbst Objekte sind. Probieren Sie das Folgende als Referenz aus:

x = "test";
console.log(x.foo);
x.foo = 12;
console.log(x.foo);

In beiden console.log finden Sie den folgenden Wert undefined .

0 Stimmen

Geben Sie 5 in die Funktion ein und rufen Sie theParam.toPrecision(4) auf, und es funktioniert. Das bedeutet, dass es sich um ein Objekt handelt. Wenn es in der Lage ist, etwas aus seinem Prototyp zu verwenden, dann muss es ein Objekt sein. Es ist nicht wie in Ruby, wo man 5.someMethod() machen kann, sondern jede Variable ist in ein entsprechendes Objekt verpackt.

0 Stimmen

Zu Beginn ist es kein Objekt, aber wenn eine Methode aufgerufen wird, wird es umhüllt.

0 Stimmen

Der Wrapper wird verworfen, sobald der Aufruf abgeschlossen ist. Er ist jedoch nur eine Konvention und ersetzt nicht die ursprüngliche Zeichenfolge durch ein Objekt.

20voto

zangw Punkte 36978

In JavaScript wird der Typ des Wertes ausschließlich steuert, ob dieser Wert von Wert-Kopie oder durch Referenz-Kopie .

Primitive Werte werden immer durch Wertkopie zugewiesen/übergeben :

  • null
  • undefined
  • String
  • Nummer
  • boolean
  • Symbol in ES6

Zusammengesetzte Werte werden immer durch 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]

In dem obigen Ausschnitt, weil 2 ist ein skalares Primitivum, a enthält eine erste Kopie dieses Wertes, und b wird eine weitere Kopie des Wertes zugewiesen. Beim Ändern b ändern Sie in keiner Weise den Wert in a .

Aber beide c y d sind getrennte Verweise auf denselben gemeinsamen Wert [1,2,3] der ein zusammengesetzter Wert ist. Es ist wichtig zu beachten, dass weder c noch d mehr "besitzt" die [1,2,3] Wert - beide sind nur gleichrangige Verweise auf den Wert. Wenn also eine der beiden Referenzen zum Ändern verwendet wird ( .push(4) ) die eigentliche gemeinsame array Wert selbst, betrifft es nur den einen gemeinsamen Wert, 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 den Auftrag erteilen b = [4,5,6] tun wir absolut nichts, um zu beeinflussen, wo a noch referenziert ( [1,2,3] ). Um das zu tun, b müsste ein Zeiger sein auf a statt eines Verweises auf den array -- aber eine solche Möglichkeit gibt es in JS nicht!

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 weist es eine Kopie der Datei a Bezugnahme auf x . x y a sind separate Verweise, die auf dieselbe [1,2,3] Wert. Jetzt können wir innerhalb der Funktion diesen Verweis verwenden, um den Wert selbst zu verändern ( push(4) ). Aber wenn wir die Zuordnung vornehmen x = [4,5,6] hat dies keinen Einfluss darauf, wo die ursprüngliche Referenz a zeigt - immer noch auf die (jetzt geänderte) [1,2,3,4] Wert.

Um effektiv einen zusammengesetzten Wert zu übergeben (wie eine array ) durch value-copy, 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 durch Referenzkopie übergeben werden kann

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

var obj = {
    a: 2
};

foo( obj );

obj.a; // 42

Hier, obj dient als Wrapper für die skalare primitive Eigenschaft a . Bei Übergabe an foo(..) eine Kopie der obj Referenz übergeben und auf den wrapper Parameter. Wir können nun den wrapper Referenz, um auf das gemeinsame Objekt zuzugreifen und seine Eigenschaft zu aktualisieren. Nachdem die Funktion beendet ist, obj.a wird der aktualisierte Wert angezeigt 42 .

Quelle

0 Stimmen

Zunächst heißt es: "Zusammengesetzte Werte werden immer durch Referenzkopie zugewiesen/übergeben", und dann heißt es: "weist eine kopieren. des Verweises auf x". Bei dem, was Sie als "zusammengesetzten Wert" bezeichnen, ist der eigentliche Variablenwert die Referenz (d.h. der Speicherzeiger). Wie Sie erklärt haben, wird der Verweis kopiert... also werden die Variablen Wert wird kopiert , wobei erneut betont wird, dass der Verweis der Wert ist. Das bedeutet, dass JavaScript für alle Typen pass-by-value ist. Pass-by-Value bedeutet, dass eine Kopie des Wertes der Variablen übergeben wird. Es spielt keine Rolle, dass der Wert ein Verweis auf ein Objekt / Array ist.

0 Stimmen

Sie führen eine neue Terminologie ein (Wertkopie/Referenzkopie), und das macht die Sache nur noch komplexer. Es gibt nur Kopien, Punkt. Wenn Sie ein Primitiv übergeben, übergeben Sie eine Kopie der tatsächlichen Primitivdaten, wenn Sie ein Objekt übergeben, übergeben Sie eine Kopie des Speicherplatzes des Objekts. Das ist alles, was man sagen muss. Alles andere verwirrt die Leute nur noch mehr.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X