einführen
In diesem Kapitel werden wir die Strategie erläutern, Parameter an Funktionsfunktionen in ECMascript zu übergeben.
In der Informatik wird diese Strategie allgemein als "Evaluierungsstrategie" bezeichnet (Onkel -Anmerkung: Einige Leute sagen, sie wird in die Bewertungsstrategie übersetzt, während andere sie in die Zuordnungsstrategie übersetzen. Wenn man die folgenden Inhalte betrachtet, ist es meiner Meinung nach angemessener, sie als Zuordnungsstrategie zu bezeichnen. Wie auch immer, der Titel sollte als Bewertungsstrategie geschrieben werden, die für alle einfach zu verstehen ist). In Programmiersprachen werden beispielsweise Regeln für die Bewertung oder Berechnungsausdrücke festgelegt. Eine Strategie zum Übergeben von Parametern an eine Funktion ist ein Sonderfall.
http://dmitrysoshnikov.com/ecmascript/chapter-8-evaluation-strategy/
Der Grund für das Schreiben dieses Artikels ist, dass jemand im Forum darum gebeten wurde, einige Strategien für die Übergabe von Parametern genau zu erklären. Wir haben hier die entsprechende Definition gegeben, in der Hoffnung, dass sie für alle hilfreich sein wird.
Viele Programmierer sind davon überzeugt, dass in JavaScript (auch in einigen anderen Sprachen) Objekte mit Referenz übergeben werden, während der ursprüngliche Werttyp von Werten übergeben wird. Darüber hinaus sprechen viele Artikel über diese "Tatsache", aber viele Menschen verstehen diesen Begriff wirklich und wie viele sind richtig? Wir werden es in diesem Artikel einzeln erklären.
Allgemeine Theorie
Es ist zu beachten, dass es in der Zuordnungstheorie im Allgemeinen zwei Zuordnungsstrategien gibt: streng - bedeutet, dass die Parameter vor Eingabe des Programms berechnet werden; Nicht -Streng - bedeutet, dass die Berechnung der Parameter basierend auf den Berechnungsanforderungen berechnet wird (dh der Berechnung entspricht der Berechnung).
Dann betrachten wir hier die grundlegende Funktionsparameterübertragungsstrategie, die aus dem Ausgangspunkt von ECMascript sehr wichtig ist. Das erste, was zu beachten ist, ist, dass strenge Strategien für das Passieren von Parametern in ECMascript verwendet werden (auch in anderen Sprachen wie C, Java, Python und Ruby).
Darüber hinaus ist die Berechnungsreihenfolge der bestandenen Parameter auch sehr wichtig - in ECMascript ist sie von links nach rechts und die in andere Sprachen implementierte Einführungsreihenfolge (von rechts nach rechts) kann ebenfalls verwendet werden.
Die strenge Übertragungsstrategie ist ebenfalls in mehrere Saatgutstrategien unterteilt, und wir werden die wichtigsten Strategien in diesem Kapitel ausführlich diskutieren.
Nicht alle nachstehend erörterten Strategien werden in ECMascript verwendet. Bei der Erörterung des spezifischen Verhaltens dieser Strategien haben wir Pseudo-Code verwendet, um dies zu zeigen.
Nach Wert passieren
Durch den Wert von Wert sind viele Entwickler bekannt, dass der Wert des Parameters eine Kopie des vom Anrufer übergebenen Objektwert ist. Durch das Ändern des Wertes des Parameters innerhalb der Funktion wird das externe Objekt nicht beeinflusst (den Wert des Parameters außerhalb). Im Allgemeinen wird neuer Speicher neu zugefügt (wir achten nicht darauf, wie zugewiesener Speicher implementiert wird - es ist auch die Stapel- oder Dynamic -Speicherzuweisung). Der Wert des neuen Speicherblocks ist eine Kopie des externen Objekts, und sein Wert wird in der Funktion verwendet.
Die Codekopie lautet wie folgt:
Bar = 10
Verfahren Foo (Bararg):
Bararg = 20;
Ende
Foo (Bar)
// Ändern Sie den Wert innerhalb von FOO nicht den Wert der internen Balken
Druck (Bar) // 10
Wenn die Parameter der Funktion jedoch nicht der ursprüngliche Wert, sondern ein komplexes strukturelles Objekt sind, führt dies zu großen Leistungsproblemen. C ++ hat dieses Problem. Wenn Sie die Struktur als Wert in die Funktion übergeben, handelt es sich um eine vollständige Kopie.
Lassen Sie uns ein allgemeines Beispiel geben, um die folgende Zuordnungsstrategie zu testen. Denken Sie an eine Funktion, die 2 Parameter akzeptiert. Der erste Parameter ist der Wert des Objekts, und der zweite ist eine booleale Marke, um zu markieren, ob das Objekt vollständig geändert wird (das Objekt um das Objekt neu zusigniert) oder nur einige Eigenschaften des Objekts werden geändert.
Die Codekopie lautet wie folgt:
// Hinweis: Im Folgenden finden Sie alle Pseudo-Code, nicht die JS-Implementierung
bar = {
x: 10,
Y: 20
}
Verfahren Foo (Bararg, isurlchange):
Wenn isfullChange:
bararg = {z: 1, q: 2}
Ausfahrt
Ende
bararg.x = 100
Bararg.y = 200
Ende
Foo (Bar)
// Nach Wert bestehen, werden externe Objekte nicht geändert
print (bar) // {x: 10, y: 20}
// Ändern Sie das Objekt vollständig (weisen Sie einen neuen Wert zu)
Foo (Bar, wahr)
// Auch keine Änderung
print (bar) // {x: 10, y: 20} anstelle von {z: 1, q: 2}
Durch Referenz passieren
Eine weitere bekannte Pass-by-Referenz ist keine Wertkopie, sondern ein implizite Verweis auf das Objekt, wie die direkte Referenzadresse des Objekts außerhalb. Alle Änderungen der Parameter innerhalb der Funktion beeinflussen den Wert des Objekts außerhalb der Funktion, da beide auf das gleiche Objekt, dh der Parameter, einem Alias des externen Objekts äquivalent sind.
Pseudocode:
Die Codekopie lautet wie folgt:
Verfahren Foo (Bararg, isurlchange):
Wenn isfullChange:
bararg = {z: 1, q: 2}
Ausfahrt
Ende
bararg.x = 100
Bararg.y = 200
Ende
// Verwenden Sie dasselbe Objekt wie oben
bar = {
x: 10,
Y: 20
}
// Das Ergebnis des Anrufs durch Bezugnahme ist wie folgt:
Foo (Bar)
// Der Eigenschaftswert des Objekts wurde geändert
print (bar) // {x: 100, y: 200}
// Neuzuweisungen neue Werte beeinflussen auch das Objekt
Foo (Bar, wahr)
// Dieses Objekt ist bereits ein neues Objekt
print (balken) // {z: 1, q: 2}
Diese Strategie kann komplexe Objekte effizienter passieren, wie z. B. große Strukturobjekte mit großen Chargen von Attributen.
Rufen Sie an, indem Sie teilen
Jeder kennt die beiden oben genannten Strategien, aber Sie wissen möglicherweise nicht, welche Strategie Sie hier sprechen möchten (tatsächlich ist es eine akademische Strategie). Wir werden jedoch bald feststellen, dass dies genau die Strategie ist, die eine Schlüsselrolle bei der Parameterablieferungsstrategie in ECMAScript spielt.
Diese Strategie hat auch einige Synonyme: "Pass by Object" oder "Pass by Objektfreigabe".
Diese Strategie wurde 1974 von Barbara Liskov für die CLU -Programmiersprache vorgeschlagen.
Der entscheidende Punkt dieser Strategie ist, dass die Funktion eine Kopie (Kopie) des Objekts empfängt und die Referenzkopie den formalen Parametern und ihren Werten zugeordnet ist.
Wir können die Referenzen, die hier "Pass by Reference" erscheinen, nicht aufrufen, da die von der Funktion empfangenen Parameter nicht direkte Objekt -Alias, sondern eine Kopie der Referenzadresse sind.
Der wichtigste Unterschied besteht darin, dass die Funktion neue Werte in den Parameter im Inneren nicht zuordnen (wie der Fall im obigen Beispiel übergeben wird), sondern weil der Parameter eine Adresskopie ist, ist das gleiche Objekt, das außerhalb und innen zugegriffen wird (z. B. das externe Objekt, keine vollständige Kopie, wie Sie nach dem Wert übergeben möchten). Durch das Ändern des Attributwerts des Parameterobjekts wirkt sich das externe Objekt aus.
Die Codekopie lautet wie folgt:
Verfahren Foo (Bararg, isurlchange):
Wenn isfullChange:
bararg = {z: 1, q: 2}
Ausfahrt
Ende
bararg.x = 100
Bararg.y = 200
Ende
// Verwenden Sie diese Objektstruktur immer noch
bar = {
x: 10,
Y: 20
}
// Durchgabe des Beitrags wirkt sich auf das Objekt aus
Foo (Bar)
// Die Eigenschaften des Objekts wurden geändert
print (bar) // {x: 100, y: 200}
// Neuzuweisung funktioniert nicht
Foo (Bar, wahr)
// immer noch der obige Wert
print (bar) // {x: 100, y: 200}
Die Annahme dieser Verarbeitung ist, dass die in den meisten Sprachen verwendeten Objekte nicht die ursprünglichen Werte sind.
Pass by Aktie ist ein Sonderfall des Wertes von Wert
Die Strategie der Bereitstellung durch Teilen wird in vielen Sprachen verwendet: Java, ECMascript, Python, Ruby, Visual Basic usw. Darüber hinaus hat die Python -Community diesen Begriff verwendet und kann in anderen Sprachen verwendet werden, da andere Namen dazu neigen, sich verwirrt zu fühlen. In den meisten Fällen, beispielsweise in Java, ECMascript oder Visual Basic, wird diese Strategie auch als Pass -by -Wert bezeichnet - was bedeutet: Sonderwert - Referenzkopie (Kopie).
Einerseits ist es so - die an die Funktion übergebenen Parameter sind nur ein Name des gebundenen Werts (Referenzadresse) und wirken sich nicht auf das externe Objekt aus.
Andererseits werden diese Begriffe wirklich als falsch angesehen, ohne sich damit zu befassen, da viele Foren darüber sprechen, wie Objekte an JavaScript -Funktionen weitergegeben werden können).
Es gibt tatsächlich ein Sprichwort in der allgemeinen Theorie, das nach Wert vergeht: aber zu diesem Zeitpunkt ist dieser Wert das, was wir die Adresskopie (Kopie) nennen, sodass er die Regeln nicht verstößt.
In Ruby wird diese Strategie als PASS durch Referenz bezeichnet. Lassen Sie mich erneut sagen: Es wird nicht in Bezug auf eine Kopie einer großen Struktur (zum Beispiel nicht nach Wert) übergeben, und andererseits verarbeiten wir keine Verweise auf das ursprüngliche Objekt und können es nicht ändern. Daher kann dieses Konzept der Kreuzzeit verwirrender sein.
Es gibt keinen speziellen Fall, der in der Theorie in der Theorie wie ein von Wert übergebener Sonderfall verabschiedet wird.
Es ist jedoch immer noch notwendig, diese Strategien in den oben genannten Technologien zu verstehen (Java, Ecmascript, Python, Ruby, Other). Tatsächlich besteht die Strategie, die sie verwenden, durch das Teilen zu bestehen.
Drücken Sie Share und Zeiger
Für с/с ++ entspricht diese Strategie mit dem Bestehen des Zeigerwerts, aber es gibt einen wichtigen Unterschied - diese Strategie kann die Zeiger Dereference und die Objekte vollständig ändern. Im Allgemeinen ist es jedoch im Allgemeinen, einem neuen Speicherblock einen Wert (Adresse) Zeiger zuzuweisen (dh der zuvor verwiesene Speicherblock, der zuvor vermerkt ist). Durch das Ändern der Objekteigenschaften durch einen Zeiger wirkt sich das externe Objekt von Adong aus.
Also, und Zeigerkategorien können wir deutlich erkennen, dass dies vom Adresswert übergeben wird. In diesem Fall ist die Durchführung durch das Teilen nur "synthetischer Zucker", wie das Verhalten der Zeigerzuordnung (jedoch nicht die Derreferenz) oder die Änderung von Eigenschaften wie Referenzen (keine Dereferenzvorgänge erforderlich), manchmal kann es als "sicherer Zeiger" bezeichnet werden.
С/с + + weist jedoch auch spezielle syntaktische Zucker auf, wenn sie sich auf Objekteigenschaften ohne Dereseferenzen offensichtlicher Hinweise beziehen:
Die Codekopie lautet wie folgt:
obj-> x anstelle von (*obj) .x
Diese Ideologie, die am engsten mit C ++ verwandt ist, ist aus der Implementierung von "intelligenten Zeigern" ersichtlich. In Boost :: Shared_ptr werden beispielsweise der Zuordnungsoperator und der Kopierkonstruktor überladen, und der Referenzschalter des Objekts wird auch zum Löschen des Objekts über GC verwendet. Dieser Datentyp hat sogar einen ähnlichen Namen - Share_Ptr.
Implementierung von ECMascript
Jetzt kennen wir die Richtlinie, Objekte als Parameter in ECMascript zu übergeben. Wie wir jedoch erwähnt haben, nennen die ECMAScript -Entwickler es jedoch im Allgemeinen: Übergeben nach Wert, außer dass der Wert eine Kopie der Referenzadresse ist.
JavaScript Inventor Brendan Ashe schrieb auch: Was übergeben wird, ist eine Kopie der Referenz (eine Kopie der Adresse). Was alle im Forum erwähnt haben, ist auch unter dieser Erklärung korrekt.
Genauer gesagt kann dieses Verhalten als einfache Aufgabe verstanden werden. Wir können sehen, dass die Interna völlig unterschiedliche Objekte sind, aber der gleiche Wert wird verwiesen - dh die Adresskopie.
ECMascript -Code:
Die Codekopie lautet wie folgt:
var foo = {x: 10, y: 20};
var bar = foo;
alarm (bar === foo); // WAHR
bar.x = 100;
bar.y = 200;
Alert ([foo.x, foo.y]); // [100, 200]
Das heißt, zwei Bezeichnungen (Namensbindung) sind im Speicher an dasselbe Objekt gebunden und teilen dieses Objekt:
FOO -Wert: addr (0xff) => {x: 100, y: 200} (Adresse 0xff) <= Balkenwert: addr (0xff)
Für die Neuzuweisung ist die Bindung eine neue Objektkennung (neue Adresse), ohne das zuvor gebundene Objekt zu beeinflussen:
Die Codekopie lautet wie folgt:
bar = {z: 1, q: 2};
Alert ([foo.x, foo.y]); // [100, 200] Keine Änderung
Alert ([bar.z, bar.q]); // [1, 2] Aber jetzt ist die Referenz ein neues Objekt
Das heißt, Foo und Bar haben jetzt unterschiedliche Werte und unterschiedliche Adressen:
Die Codekopie lautet wie folgt:
FOO -Wert: addr (0xff) => {x: 100, y: 200} (Adresse 0xff)
Balkenwert: addr (0xfa) => {z: 1, q: 2} (Adresse 0xfa)
Lassen Sie mich erneut betonen, dass der Wert des hier genannten Objekts die Adresse ist, nicht die Objektstruktur selbst und die Zuweisung der Variablen einer anderen Variablen - eine Referenz auf den zugewiesenen Wert. Daher beziehen sich die beiden Variablen auf dieselbe Speicheradresse. Die nächste Zuordnung ist die neue Adresse, die die Bindung an die Adresse des alten Objekts auflösen und dann an die Adresse des neuen Objekts binden. Dies ist der wichtigste Unterschied zwischen dem Übergang durch Referenz.
Wenn wir nur die vom Ecma-262-Standard bereitgestellte Abstraktionsebene betrachten, sehen wir nur das Konzept des "Wertes" im Algorithmus, der den bestandenen "Wert" implementiert (kann der ursprüngliche Wert oder das Objekt sein), aber gemäß unserer obigen Definition kann es auch vollständig als "übergeben" bezeichnet werden ", da die Referenzaktion auch ein Wert ist.
Um Missverständnisse zu vermeiden (warum die Eigenschaften externer Objekte in der Funktion geändert werden können), müssen die Details zur Implementierungsebene hier noch berücksichtigt werden - was wir sehen, wird durch das Teilen oder mit anderen Worten übergeben - übergeben von einem sicheren Zeiger, der nicht den Abschluss und das Objekt geändert werden kann, aber der Eigenschaftswert des Objekts kann geändert werden.
Begriff Version
Definieren wir die Begriff Version dieser Richtlinie in ECMascript.
Es kann als "Pass by Value" bezeichnet werden - der hier erwähnte Wert ist ein Sonderfall, dh der Wert ist eine Adresskopie. Aus dieser Ebene können wir sagen: Objekte in ECMascript, außer Ausnahmen werden nach Wert übergeben, was tatsächlich die Ebene der ECMascript -Abstraktion ist.
Oder in diesem Fall wird es ausdrücklich als "durch teilen" bezeichnet. Dadurch können Sie den Unterschied zwischen traditionellem Bestehen nach Wert und Übergabe von Referenz sehen. Diese Situation kann in zwei Situationen unterteilt werden: 1: Der ursprüngliche Wert wird nach Wert übergeben; 2: Das Objekt wird durch Freigabe übergeben.
Die Phrase "Um zu funktionieren, indem sie Typen referenzieren" hat nichts mit ECMascript zu tun, und es ist falsch.
abschließend
Ich hoffe, dieser Beitrag hilft dabei, weitere Details auf Makroebene und -implementierung in ECMascript zu erfahren. Wie immer, wenn es Fragen gibt, können Sie sie gerne besprechen.