2010-11-07 19 views
15

Also ich bin neu in der Programmierung und ich versuche, JS mit dem Buch Eloquent Javascript zu lernen.JavaScript Beispielfrage: lexikalische Scoping/Schließung - Eloquent Javascript

So weit so gut, bis ich ein Beispiel mit dem folgenden Code erreicht

function makeAddFunction(amount) { 
    function add(number) { 
    return number + amount; 
    } 
    return add; 
} 

var addTwo = makeAddFunction(2); 
var addFive = makeAddFunction(5); 
show(addTwo(1) + addFive(1)); 

Anmerkung: Show wie Alarm ist, es zeigt nur die Variablen auf dem Bildschirm einer JS-Konsole das Tutorial integriert hat.

Der Autor sagt, dass dies ein Beispiel ist, um zu zeigen, wie lexikalisches Scoping erlaubt, Funktionen zu synthetisieren. Chapter here

Was ich nicht verstehe ist, wie addTwo und addFive, die angeblich Variablen sind, können Parameter an die Funktionen makeAddFunction und add und insbesondere senden, wie funktioniert die Funktion add weiß, dass der Parameter die Variablen senden ist der Parameter number.

Vielen Dank für Ihre Hilfe Jungs!

+0

Es lohnt sich wahrscheinlich, dies zu lesen: http://en.wikipedia.org/wiki/Closure_(computer_science) –

Antwort

6

Ich denke, der Schlüssel zum Verständnis dieses Beispiels ist zu verstehen, dass Funktionen andere Funktionen (wie jede andere Variable) zurückgeben können. Die Dokumentation dieses Codes wird wesentlich dazu beitragen, dieses Konzept zu verstehen.

/** 
* Creates an adder function 
* @param {number} amount Amount to add 
* @return {function} Method that adds 'amount' to its argument. 
* See the documentation of add for its signature 
*/ 
function makeAddFunction(amount) {  
    /** 
    * Everytime makeAddFunction is called, a new instance of add is created 
    * (and returned) that holds on to its copy of 'amount' (through the closure) 
    * @param {number} number value to add to 'amount' 
    * @return {number} 'amount' + 'number' 
    */ 
    return function add(number) { 
    return number + amount; 
    }; 
} 

// addTwo now is a reference to a function that when called 
// adds 2 to whatever is passed in 
var addTwo = makeAddFunction(2); 
// addFive Adds 5 to its argument 
var addFive = makeAddFunction(5); 
// addTwo(1) = 3, addFive(1) = 6, therefore, output is 9 
show(addTwo(1) + addFive(1)); 
8

addTwo und addFive sind Variablen - aber sie sind Funktionsvariablen. Schauen Sie sich typeof(addTwo) an - es ist eine Funktion. Es ist wie, wenn Sie tat dies:

var addTwo = function(x) { return x + 2; }; 

Es ist das gleiche wie folgt aus:

function addTwo(x) { return x + 2; } 

(Edit: Wie Šime wies darauf hin, sie sind nicht genau das gleiche Siehe here für eine Erklärung der. Unterschied zwischen den beiden.)

Das Beispiel wird hoffentlich Sinn ergeben, sobald Sie das verstehen. Sie können auch seltsame Dinge tun, wie diese, eine anonyme Funktion erklärt und es sofort Berufung auf:

var seven = function(x) { return x + 2; }(5); 

was wörtlich heißt, an der Maschinencode-Ebene physischen, genau das gleiche wie: , auf der für alle gleichwertig ist Zwecke relevant zu dieser Frage:

function addTwo(x) { return x + 2; } 
var seven = addTwo(5); 

Edit:

Vielleicht eine weniger verwirrend "Prequel" dazu ist die folgende:

function makeTheAddTwoFunction() 
{ 
    return function(x) { return x + 2; } 
} 

var addTwo = makeTheAddTwoFunction(); 

Dies ist albern, dient aber zur Veranschaulichung von Funktionen, die Funktionen machen. Natürlich wird diese Art von Funktion normalerweise Argumente akzeptieren, so dass sie jedes Mal verschiedene Funktionen ausführen kann, aber da gehen Sie.

+4

@Ian Die ersten beiden Codezeilen sind nicht gleichwertig. Sie sind nur * fast * gleich. –

+0

@ Šime Können Sie den Unterschied erklären? Beide definieren das Symbol "addTwo" im aktuellen Bereich und setzen seinen Wert auf die gleiche Funktion. Ich habe diese immer als austauschbar behandelt, vielleicht zu meinem Nachteil. –

+0

Entschuldigung, die angegebenen Beispiele sind NICHT gleich. Sie vergleichen die Zuweisung einer Variablen mit einer Funktion, indem Sie einer Funktion einen Namen geben. Sie sind nicht gleich! Sie können verschiedene Werte für * dieses * haben; die einer Variablen zugewiesene Funktion kann neu zugewiesen werden, Funktion nicht so sehr. ** Erinnere dich **, dass es sich bei diesem SO Q um die Feinheiten der Sprache handelt, also sind diese Probleme wichtig. –

9

In JavaScript ist eine Funktion ein erstklassiges Objekt, dh es kann weitergegeben, einer Variablen zugewiesen, usw. Die Variablen addTwo und addFive enthalten Funktionen. Diese Funktionen werden von der Factory-Funktion makeAddFunction generiert.

Die Funktionen, die addTwo und addFive enthalten, enthalten den Gültigkeitsbereich, der bei der Erstellung vorhanden war. Das heißt, wenn addTwo zum Beispiel erstellt wurde, war der Parameter "amount" 2.So AddTwo im Wesentlichen vor, ist die folgende Funktion:

function addTwo(number) { 
    return number + 2; 
} 

Wenn jemand anruft AddTwo(), es ist nicht alles vorbei zurück zu makeAddFunction. MakeAddFunction wurde bereits ausgeführt und ist beendet. Der in createAddFunction erstellte Bereich (in dem "amount" gleich 2 ist) bleibt jedoch in der addTwo-Funktion bestehen.

+0

Fantastisch! Ich war schielend und sabberte über dieses Beispiel (nicht deins, das von Eloquent JavaScript), aber deine Erklärung hat es kristallklar gemacht! Dein ist die erste Erklärung, die ich gesehen (und verstanden habe), die die Tatsache erwähnt, dass der Betrag "eingebrannt" wird, wenn der "Funktionshersteller" die interne Funktion, die er zurückgibt, baut. Vielen Dank!!! – mbm29414

+0

Ich musste es wirklich für ein paar Minuten überarbeiten, um es zu verstehen, aber das ist die klarste Erklärung hier. Es hat mir geholfen, 'makeAddFunction()' wie einen Konstruktor zu sehen, indem es neue Instanzen von 'add()' zurückgibt. – gmeben

3

Re: Was ich nicht verstehe ist, wie addTwo und addFive, die angeblich Variablen sind, Parameter an die Funktionen makeAddFunction senden können?

addTwo und addFive sind Variablen. Aber ihre Werte sind keine einfachen Skalare (Zahlen, Strings usw.). Ihre Werte sind vielmehr Funktionen. Da ihre Werte Funktionen sind, ist es in Ordnung, diese Funktionen aufzurufen. ZB addTwo(1)

Re: genauer gesagt, wie funktioniert die Funktion Add weiß, dass der Parameter die Variablen zu senden sind, ist der Parameter Nummer?

Die Funktion add ruft ihren ersten Parameter an. Wenn Sie die Funktion später über eine Variable wie zB addOne aufrufen, wird der erste Parameter für addOne Nummer.

ps Wenn Sie zu sich selbst denken, "Selbst, das ist ziemlich schwierig!" Dann hast du recht - und das ist der ganze Zweck des Beispiels, etwas Schwieriges zu zeigen. Wie oft Sie diese Technik verwenden, kann von nie zu oft variieren.

0

Die beste Art und Weise, wie diese von einem Stück Code zu denken ist zu Ersatz Werte und Interpet im Kopf

// when this one is invoked 
var addTwo = makeAddFunction(2); 

// makeAddFunction 
// becomes something like 
function makeAddFunction(2) { 
    function add(number) { 
    return number + 2; 
    } 
    // return a function, that adds 
    // 2 to every number it gets 
    return add; 
} 

// therefore this function call 
// will add 2 to 1 and return 3 
addTwo(1); 
0

Wie immer hier die Jibbring notes on JavaScript Closures sind. Er beschreibt Bereiche, Ausführungskontexte, Variable/Eigenschaft Auflösung, etc ...

Während JavaScript Schließungen lexikalischer sind, Ausführungskontexte (welche Eigenschaften enthalten kann) gebunden sind (man denke Python oder Ruby) und nicht nur „freie Variablen "(wie es bei C# oder Scala der Fall ist). Dies ist der Grund, warum neue Variablen nur in neue Funktionsbereiche eingeführt werden können. (Moderne Mozilla-Implementierungen führen let ein).