2017-07-12 16 views
3

Hier ist ein kleiner Ausschnitt des Codes, wo ich die Verschlussfunktion fühle eine seltsame Verhalten hat ...JavaScript Closure falsches Verhalten

var arr = [5, 6, 7, 8, 9, 0]; 
 
var someFn; 
 

 
arr.forEach(function(val, idx) { 
 
    if (!someFn) { 
 
    someFn = function() { 
 
     console.log(`B: ${idx} : ${val}`); 
 
    }; 
 
    } 
 
    console.log(`A: ${idx} : ${val}`); 
 
    someFn(); 
 
});

Die letzte Ausgabe der Konsole ist ...

A: 0 : 5 
B: 0 : 5 
A: 1 : 6 
B: 0 : 5 
A: 2 : 7 
B: 0 : 5 
A: 3 : 8 
B: 0 : 5 
A: 4 : 9 
B: 0 : 5 
A: 5 : 0 
B: 0 : 5 

ich erwarte someFn, um den inkrementellen Wert zu verarbeiten, wenn forEach verarbeitet, aber es gibt immer den ersten Wert aus, der "idx: 0, val: 5" ist.

Ich denke nicht das das richtige Verhalten ist, weil someFn eine Schließung zu schaffen, die die Variablen umschließt idx und val und diese beiden Variablen in der äußeren Funktion zu verändern.

Schätzen Sie, wenn jemand dieses Verhalten freundlicherweise erklären kann.

+0

Ich denke, es ist, weil Sie 'someFn erklärt () 'mit einem aktuellen Wert von 'idx' und 'val' und sobald Sie es weiter aufrufen, übergeben Sie keine neuen Werte von ihnen. – Lixus

+0

Wenn Ihr Zustand es vermasselt: Verwenden Sie dies: var arr = [5,6,7,8,9,0]; var someFn; arr.forEach (function (val, idx) { someFn = function() { console.log ('B: $ {idx}: $ {val}'); }; someFn(); }); und es wird funktionieren. –

+1

@baao das Problem hat nichts mit ** Template-Literalen ** zu tun. Also stimme ich das wieder zu öffnen. –

Antwort

0

Nach dieser other answer auf SO:

ein Verschluss ist ein Stapelrahmen, die zugeordnet wird, wenn eine Funktion seiner Ausführung beginnt ...

Also jeden Funktionsaufruf einen eigenen Verschluss schafft.

Was macht forEach ist, dass es eine Funktion (Callback) und ruft es mehrmals (Übergabe des Elements aus dem Array zusammen mit seinem Index und dem Array). Jede Iteration von forEach erstellt also einen neuen Abschluss.

Sie definieren someFn bei der ersten Iteration (nie danach erneut deklariert), also ist der Abschluss, in dem es gefangen ist, der Abschluss der ersten Iteration. Daher sind die einzigen verfügbaren Werte diejenigen der ersten Iteration.

Die Schließung bezieht sich nicht auf die Funktion selbst, sie ist mit ihren Aufrufen verbunden.

Beispiel:

function theFunction(value) { 
 
    return function() { 
 
    return value; 
 
    }; 
 
} 
 

 
var someFn1 = theFunction("Ibrahim"); 
 
var someFn2 = theFunction("John"); 
 

 
console.log("someFn1: ", someFn1()); 
 
console.log("someFn2: ", someFn2());

Im Beispiel jeder Aufruf theFunction erstellt einen neuen Verschluss. someFn1 und someFn2, obwohl sie von derselben Funktion generiert werden, aber keinen Zugriff auf denselben Abschluss haben.

Das Äquivalent zu theFunction in Ihrem Code ist die anounymous Funktion, die an forEach übergeben wird, die ausgeführt wird (und so clousures erstellt), so oft Elemente in dem Array vorhanden sind.

+0

Ich verstehe das. Aber ich glaube, deine Antwort ist richtig. Obwohl ich denke, dass ich Schließungen wirklich gut verstehe, aber es ist so einfach, auf solche Fallen hereinzufallen. Danke und ich habe für dich gestimmt. – Praj

+0

Gern geschehen! Yeah Verschlüsse können knifflig sein. –

0

erwarte ich someFn einen Verschluss zu schaffen, die die Variablen idx und val und beide diese Variablen umschließt in der äußeren Funktion zu verändern.

Nein, sie ändern sich nicht. Sie sind neue Variablen, die bei jedem Aufruf der äußeren Funktion instanziiert werden. Die beiden Variablen aus der ersten Iteration, über die der dort erstellte Abschluss geschlossen wurde, behalten ihre Werte bei.

das erwartete Verhalten zu erhalten, können Sie eine Schleife ohne eine Funktion verwenden, in dem Sie nur zwei Variablen deklarieren:

var arr = [5, 6, 7, 8, 9, 0]; 

for (var [idx, val] of arr.entries()) { 
// ^^^^^^^^^^^^^^ global variables 
    if (!someFn) { 
    var someFn = function() { 
     console.log(`B: ${idx} : ${val}`); 
    }; 
    } 
    console.log(`A: ${idx} : ${val}`); 
    someFn(); 
} 

Obwohl usually that's exactly what we try to prevent :-)

Verwandte Themen