581 Stimmen

JavaScript-Schließungen vs. anonyme Funktionen

Ein Freund von mir und ich diskutieren gerade darüber, was ein Abschluss in JS ist und was nicht. Wir wollen nur sicherstellen, dass wir es wirklich richtig verstehen.

Nehmen wir dieses Beispiel. Wir haben eine Zählschleife und wollen die Zählervariable verzögert auf der Konsole ausgeben. Deshalb verwenden wir setTimeout y Verschlüsse um den Wert der Zählervariablen zu erfassen, um sicherzustellen, dass sie nicht N-mal den Wert N ausgibt.

Die falsche Lösung ohne Verschlüsse oder irgendetwas in der Nähe von Verschlüsse wäre:

for(var i = 0; i < 10; i++) {
    setTimeout(function() {
        console.log(i);
    }, 1000);
}

was natürlich den 10-fachen Wert von i nach der Schleife, nämlich 10.

Das war sein Versuch:

for(var i = 0; i < 10; i++) {
    (function(){
        var i2 = i;
        setTimeout(function(){
            console.log(i2);
        }, 1000)
    })();
}

Druck von 0 bis 9 wie erwartet.

Ich habe ihm gesagt, dass er nicht mit einem Verschluss zu erfassen i aber er besteht darauf, dass er es ist. Ich habe bewiesen, dass er keine Verschlüsse indem man den Körper der for-Schleife in eine andere setTimeout (Übergabe seiner anonymen Funktion an setTimeout ), wobei wieder 10 mal 10 gedruckt wird. Dasselbe gilt, wenn ich seine Funktion in einer var und führen sie aus nach die Schleife und druckt ebenfalls 10 mal 10. Mein Argument ist also, dass er hat nicht wirklich erfassen den Wert von i und macht seine Version no einen Abschluss.

Das war mein Versuch:

for(var i = 0; i < 10; i++) {
    setTimeout((function(i2){
        return function() {
            console.log(i2);
        }
    })(i), 1000);
}

Ich erfasse also i (genannt i2 im Rahmen der Schließung), aber jetzt habe ich return eine andere Funktion und geben diese weiter. In meinem Fall fängt die an setTimeout übergebene Funktion wirklich i .

Wer verwendet nun Verschlüsse und wer nicht?

Beachten Sie, dass beide Lösungen verzögert 0 bis 9 auf der Konsole ausgeben, also das ursprüngliche Problem lösen, aber wir wollen verstehen, welche dieser beiden Lösungen verwendet Verschlüsse um dies zu erreichen.

4voto

ekim Punkte 41

Betrachten Sie das Folgende. Damit wird eine Funktion erstellt und wiederhergestellt f die sich am i , aber andere!:

i=100;

f=function(i){return function(){return ++i}}(0);
alert([f,f(),f(),f(),f(),f(),f(),f(),f(),f(),f()].join('\n\n'));

f=function(i){return new Function('return ++i')}(0);        /*  function declarations ~= expressions! */
alert([f,f(),f(),f(),f(),f(),f(),f(),f(),f(),f()].join('\n\n'));

während die folgende auf "a" Funktion "selbst" schließt
( selbst! der Ausschnitt danach verwendet einen einzigen Referenten f )

for(var i = 0; i < 10; i++) {
    setTimeout( new Function('console.log('+i+')'),  1000 );
}

oder um es noch deutlicher zu sagen:

for(var i = 0; i < 10; i++) {
    console.log(    f = new Function( 'console.log('+i+')' )    );
    setTimeout( f,  1000 );
}

NB. die letzte Definition von f es function(){ console.log(9) } vor 0 gedruckt wird.

Warnung! Das Abschlusskonzept kann eine zwanghafte Ablenkung vom Wesen der elementaren Programmierung sein:

for(var i = 0; i < 10; i++) {     setTimeout( 'console.log('+i+')',  1000 );      }

x-refs.:
Wie funktionieren die JavaScript-Schließungen?
Erläuterung der Javascript-Schließungen
Erfordert eine (JS-)Schließung eine Funktion innerhalb einer Funktion?
Wie kann man Schließungen in Javascript verstehen?
Verwechslung von lokalen und globalen Javascript-Variablen

-1voto

Eunjung Lee Punkte 1

Ich möchte mein Beispiel und eine Erklärung zu den Verschlüssen geben. Ich habe ein Python-Beispiel und zwei Abbildungen zur Veranschaulichung von Stack-Zuständen erstellt.

def maker(a, b, n):
    margin_top = 2
    padding = 4
    def message(msg):
        print('\n’ * margin_top, a * n, 
            ' ‘ * padding, msg, ' ‘ * padding, b * n)
    return message

f = maker('*', '#', 5)
g = maker('', '’, 3)
…
f('hello')
g(‘good bye!')

Die Ausgabe dieses Codes würde wie folgt aussehen:

*****      hello      #####

      good bye!    

Hier sind zwei Abbildungen, die Stapel und die an das Funktionsobjekt angehängte Schließung zeigen.

wenn die Funktion vom Hersteller zurückgegeben wird

wenn die Funktion später aufgerufen wird

Wenn die Funktion über einen Parameter oder eine nicht-lokale Variable aufgerufen wird, benötigt der Code lokale Variablenbindungen wie margin_top, padding sowie a, b, n. Um sicherzustellen, dass der Funktionscode funktioniert, sollte der Stack-Frame der Maker-Funktion, der vor langer Zeit verschwunden ist, zugänglich sein, der in der Closure gesichert ist, die wir zusammen mit dem Funktionsnachrichtenobjekt finden können.

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