2010-10-26 10 views
5

Lasst uns sagen, ich habe diese beiden Funktionen:Javascript: Re-Zuordnung einer Funktion mit einer anderen Funktion

function fnChanger(fn) { 
    fn = function() { sys.print('Changed!'); } 
} 
function foo() { 
    sys.print('Unchanged'); 
} 

Nun, wenn ich foo() nennen, ich sehe Unchanged, wie erwartet. Allerdings, wenn ich fnChanger zuerst nennen, ich sehe noch Unchanged:

fnChanger(foo); 
foo(); //Unchanged 

Nun, ich nehme an, das liegt daran, dass foo nicht auf fnChanger als Referenz übergeben zu werden, aber ich kann falsch sein.

Warum ändert sich fnChanger nicht foo, um Changed! zu drucken?
Außerdem, wie kann ich fnChangerfoo ohne zu viel chaotische Syntax ändern?

PS: Ich benutze node.js, um all diese Sachen zu testen, deshalb kommt der von.

Antwort

5

Die Zuweisung an das fn Argument macht nur, dass der Bezeichner auf die anonyme Funktion zeigt, foo im äußeren Bereich ist nicht betroffen.

Wenn Sie ein Objekt als Argument übergeben, kann man sagen "Referenzen werden nach Wert übergeben". Die Zuweisung ersetzt nur den Standort, auf den sich der Bezeichner fn bezieht.

So funktioniert die evaluation strategy in JavaScript.

Kurz vor der Zuordnung in den fnChanger Funktionen, die beiden Kennungen, die globalen foo und das fn Argument, auf das gleiche Funktionsobjekt:

 
       --------------------------------------------- 
    foo -----> |function foo { sys.print('Un changed!'); } | 
       --------------------------------------------- 
       ^
        | 
    fn ------------- 

Nach der Zuweisung wird fn zeigen Sie einfach auf den neuen Funktion:

 
       --------------------------------------------- 
    foo -----> | function foo { sys.print('Unchanged!'); } | 
       --------------------------------------------- 

       --------------------------------------- 
    fn ------> | function { sys.print('Changed!'); } | 
       --------------------------------------- 

Wie können Sie es ändern?

Nun, unter der Annahme, dass foo ist eine Funktion im globalen Bereich, können Sie etwas tun könnten:

function fnChanger(obj, name) { 
    obj[name] = function() { sys.print('Changed!'); }; 
} 

function foo() { 
    sys.print('Unchanged'); 
} 

fnChanger(this, 'foo'); 
foo(); // Changed! 

Die oben funktioniert, weil in der fnChanger Funktion benötigen wir ein Basisobjekt und eine Eigenschaftsname, Funktionen, die im globalen Ausführungskontext deklariert sind, werden als Eigenschaften des globalen Objekts gebunden, daher können wir seinen Wert auf diese Weise neu zuweisen.

Die Linie fnChanger(this, 'foo'); sollte auch im globalen Rahmen ausgeführt wird, wird es den this Wert übergeben (die in diesem Umfang auf das globale Objekt bezieht) und einen Eigenschaftsnamen, in dem Sie eine Zuordnung zu der GlobalObject.foo Kennung zu machen.

Wenn dieser Code in einer Funktion war, gibt es keine Möglichkeit, ein Basisobjekt, weil in dieser „Funktionscodeausführung Context“ erhalten kann, Funktionsdeklarationen (Variablendeklarationen und Funktion auch formale Parametern) als Eigenschaften gebunden eines nicht zugreifbaren Objekts, genannt das Variable Object (eine Kette dieser Variablenobjekte, bildet die Umfangskette), und wenn dies der Fall wäre, wäre die einzige Umgehungslösung die Verwendung von eval.

Weitere Informationen:

+0

Ja, ich fing an, das ist zu vermuten, was geschieht. Danke für die Klärung und den Link - ich wusste nie genau, wie ich das nennen soll oder wie es funktioniert. Wie kann ich das umgehen? –

+0

Ok, ich mag diesen Ansatz. Nicht so unordentlich, wie ich es mir vorgestellt habe: ein Objekt übergeben, das die zu ändernde Funktion enthält. –

2

Als @CMS Sie es nicht zuweisen innerhalb der Funktion aufgrund des Umfangs hingewiesen werden. Allerdings könnten Sie es wie folgt neu zuweisen:

var fnChanger = function() { 
    return function() { 
     alert('changed!'); 
    } 
} 

var foo = function() { 
    alert('Unchanged'); 
} 

foo = fnChanger(); 
foo(); 

example

+0

Ja, darüber nachgedacht. Ich zögere jedoch, es im echten Code zurückzugeben. Auf der einen Seite ist es sauberer, auf der anderen Seite entspricht es nicht ganz dem, was die Funktion tatsächlich tut. –

Verwandte Themen