web-dev-qa-db-de.com

Javascript-Funktion-Zeigerzuordnung

Betrachten Sie diesen Javascript-Code:

var bar = function () { alert("A"); }
var foo = bar;
bar = function () { alert("B"); };
foo();

Beim Ausführen dieses Codes bekomme ich "A". Ist dieses Verhalten Teil der Javascript-Spezifikation und kann ich mich darauf verlassen?

45
niaher

Ja das ist erwartet und beabsichtigt.

Ihre Frage ist im Grunde: Verweist foo auf bar als Zeiger oder Referenz in einer anderen Sprache?

Die Antwort ist nein: Der Wert von bar zum Zeitpunkt der Zuweisung wird foo zugewiesen.

37
cletus

In anderen Beispielen wurde nichts als Wert übergeben. alles wurde als Referenz übergeben.

bar und Foo sind beide Zeiger

Alle Variablen/Handles auf NICHT primitive Objekte in Javascript sind Zeiger. Zeiger sind in Javascript enthalten, sie sind die Standardeinstellung.

var bar = function () { alert("A"); } //bar is a pointer to function1
var foo = bar;  //pointer copied; foo is now also a pointer to function1
bar = function () { alert("B"); };  //bar points to function2
foo();  //foo is still a pointer to function1

Wenn Sie glauben, dass es sich um Kopien handelt, werden versteckte Fehler und Fehler auftreten. Besonders wenn Sie mit komplexen Objekten arbeiten. Zum Beispiel

function person(name){this.name = name}
var john = new person("john")
var backup = john
backup.name //john
john.name = "jack"
backup.name //jack, NOT john

Um wirklich zu KOPIEREN, ist ein Nicht-Primitiv in Javascript mehr Arbeit als nur a = b . Zum Beispiel:

function person(name){  this.name = name}
var john = new person("john")
var backup = new Object()
backup = JSON.parse(JSON.stringify(john))
backup.__proto__ = john.__proto__   //useful in some cases
john.name = "jack"
backup.name //john
62
siingCoder

Ich bin ein bisschen spät hier, aber ich dachte, ich würde sowieso eine Antwort geben und etwas ausprägen.

Es ist am besten, nicht in Bezug auf Zeiger und Speicherreferenzen zu denken, wenn Sie die Interna von JavaScript (oder ECMAScript) diskutieren, wenn Sie mit den Spezifikationen arbeiten. Variablen sind intern Umgebungsdatensätze und werden nach Name und nicht nach Speicheradresse gespeichert und referenziert. Was Ihre Zuweisungsanweisung intern und vom Design aus ausführt, sucht nach dem Namen des Umgebungsdatensatzes (entweder "foo" oder "bar") und weist diesem Datensatz den Wert zu.

So,

var bar = function () { alert("A"); }

weist dem Umgebungsdatensatz "bar" den Wert zu (anonyme Funktion).

var foo = bar;

ruft intern GetValue ("bar") auf, der den mit dem Datensatz "bar" verknüpften Wert abruft und diesen dann dem Datensatz "foo" zuordnet. Daher kann der ursprüngliche Wert von bar weiterhin verwendet werden, da er jetzt mit foo verknüpft ist.

Da JavaScript-Verweise nach Zeichenfolge und nicht nach Speicheradresse erfolgen, können Sie Folgendes tun:

someObject["someProperty"]

die den Wert anhand des Eigenschaftennamens nachschlägt.

19
Bob

Sie weisen den Wert einer anonymen Funktion einer Variablen zu, nicht einem Zeiger.
Wenn Sie mit Zeigern spielen möchten, können Sie Objekte verwenden, die als Verweis übergeben werden, nicht als Kopie.

Hier sind einige Beispiele:

"obj2" ist eine Referenz von "obj1", Sie ändern "obj2" und "obj1" wird geändert. Es wird false angezeigt.

var obj1 = {prop:true},
    obj2 = obj1;
obj2.prop = false;
alert(obj1.prop);

"prop" zeigt auf eine Eigenschaft, die kein Objekt ist, "prop" ist kein Zeiger auf dieses Objekt, sondern eine Kopie. Wenn Sie "prop" ändern, wird "obj1" nicht geändert. Es wird true

var obj1 = {prop:true},
    prop = obj1.prop;
prop = false;
alert(obj1.prop);

"obj2" ist eine Referenz auf die Eigenschaft "subObj" von "obj1". Wenn "obj2" geändert wird, wird "obj1" geändert. Es wird false angezeigt.

var obj1 = {subObj:{prop:true}},
    obj2 = obj1.subObj;
obj2.prop = false;
alert(obj1.subObj.prop);
5
Mic

Ja, es ist nichts Besonderes an der Tatsache, dass sich die Variablen auf Funktionen beziehen, es gibt kein Aliasing. 

var bar = 1;
var foo = bar;
bar = "something entirely different";
// foo is still 1
5

Ja, das ist das richtige Verhalten.

//create variable bar and assign a function to it
var bar = function () { alert("A"); }
//assign value of bar to the newly created variable foo
var foo = bar;
//assign a new function to the variable bar
//since foo and bar are not pointers, value of foo doesn't change
bar = function () { alert("B"); };
//call the function stored in foo
foo();
3
Amarghosh

Das sind keine Funktionszeiger (und nativ gibt es in JS keine Zeiger). Funktionen in JS können anonym sein und sind erstklassige Objekte. Daher

function () { alert("A"); }

erstellt eine anonyme Funktion, die bei Ausführung "A" anzeigt; 

var bar = function () { alert("A"); };

weisen Sie diese Funktion der Leiste zu.

var foo = bar;

ordne foo bar zu, was die Funktion "A" ist.

bar = function () { alert("B"); };

binden Sie die Leiste erneut an eine anonyme Funktion "B". Dies wirkt sich nicht auf foo oder die andere Funktion "A" aus.

foo();

Rufen Sie die in foo gespeicherte Funktion auf, die Funktion "A".


Tatsächlich in Sprachen, in denen Funktionspunkte vorhanden sind, z. C wirkt sich nicht auf foo aus. Ich weiß nicht, wo Sie auf die Idee kommen, "B" für die Neuzuweisung zu bekommen.

void A(void) { printf("A\n"); }
void B(void) { printf("B\n"); }
typedef void(*fptr_t)(void);
fptr_t foo = A;
fptr_t bar = foo;
bar = B;
foo(); // should print "A"
2
kennytm

Dies weist einer unbenannten Funktion eine Variable zu, nicht einem Zeiger auf eine Funktion 

1

Ja, Sie haben einen Zeiger auf die ursprüngliche "A" -Funktion erstellt. Wenn Sie die Leiste neu zuweisen, werden Sie neu zuweisen it, aber Sie lassen immer noch alle Verweise auf die alte Funktion allein. 

Um Ihre Frage zu beantworten, können Sie sich darauf verlassen. 

1
David Morton

Ich möchte nur hinzufügen, dass dies auch für vordefinierte benannte Funktionen funktioniert:

function myfunc() { alert("A"); }
var bar = myfunc;
var foo = bar;
bar = function () { alert("B"); };
foo();

Dies tut das Gleiche und zeigt an, dass Funktionsnamen wie Array-Namen (Zeiger) funktionieren.

0
user3015682

Führen Sie für jede FunctionDeclaration f im Code in der Reihenfolge des Quelltextes Folgendes aus:

Sei fn der Bezeichner in der FunctionDeclaration f.

Sei fo das Ergebnis der Instanziierung der FunctionDeclaration f wie in Abschnitt 13 beschrieben.

Lassen Sie funcAlreadyDeclared das Ergebnis des Aufrufs von envs konkreter HasBinding-Methode von env sein, wobei Sie fn als Argument übergeben.

Wenn funcAlreadyDeclared den Wert false hat, rufen Sie die konkrete CreateMutableBinding-Methode von env auf, und übergeben Sie als Argumente fn und configureableBindings.

Verweise

0
Paul Sweatte