2016-04-08 7 views
0

Ich habe einen guten Griff auf Verschlüsse konzeptionell, aber ein Problem ist entstanden, das ich nicht ganz verstehen kann.Verständnis der anonymen JavaScript Funktionsdefinition in Bezug auf Verschlüsse

Wenn Sie eine Funktion zu schaffen einen gewissen Wert auf eine innere Funktion zu übergeben, ohne sie auf die äußerste Funktion der Endwert verbindlich, wenn sie zurückkommt, nicht erlaubt, dies zu sein scheint:

function buildList(list) { 
    var result = []; 
    for (var i = 0; i < list.length; i++) { 
      function (x) { // this anonymous function definition... 
       var item = 'item' + list[x]; 
       result.push(
        return function() { 
         console.log(item + ' ' + list[x]); 
        }; 
       ); 
      }(i);   // and simultaneous invocation... 
    } 
    return result; 
} 

Während, wenn ich mich bewege die Verschluss vollständig innerhalb des Anrufs .push(), funktioniert alles einwandfrei aus:

function buildList(list) { 
    var result = []; 
    for (var i = 0; i < list.length; i++) { 
      result.push(
       function (x) { // wrapper now inside the call to .push() 
        var item = 'item' + list[x]; 
        return function() { 
         console.log(item + ' ' + list[x]); 
        }; 
       }(i)   // and called here... 
      ); 
    } 
    return result; 
} 

Was ich frage mich: Was Regel bin ich, wenn ich zu verletzen definieren die anonyme Funktion, die die Schließung unmittelbar innerhalb der for-Schleife wickelt im Gegensatz zu dem Aufruf von .push() ?

+0

'result.push (Return-Funktion ...' wird nie funktionieren, und es ist nicht von der Schließung zu tun,. Rückkehr ist eine Aussage, und Aussagen sind nichtig, so auch wenn es didn 't werfen für syntax, du wärst push() ing nichts. du kannst auch kein ending semi in einem push() haben, also gibt es ein paar probleme mit dem 1. code ... – dandavis

+0

Was macht "* das nicht 't scheint erlaubt sein * "bedeuten? – Amit

+0

Definieren *" funktioniert gut "*. Wie ist Ihr erwartetes Verhalten? Wie ist es in jedem Fall anders? –

Antwort

1

Mit "nicht erlaubt" nehme ich an, dass der Interpreter sich über einen Syntaxfehler beschwert. Was haben Sie im ersten Fall:

result.push(
    return function() { 
     console.log(item + ' ' + list[x]); 
    }; 
); 

Ist nicht syntaktisch gültig.

Aber selbst wenn man die Rückkehr entfernen:

function buildList(list) { 
    var result = []; 
    for (var i = 0; i < list.length; i++) { 
      function (x) { // this anonymous function definition... 
       var item = 'item' + list[x]; 
       result.push(
        function() { 
         console.log(item + ' ' + list[x]); 
        } 
       ); 
      }(i);   // and simultaneous invocation... 
    } 
} 

Sie werden immer noch einen Fehler. Dies liegt daran, dass Sie die Klammern für das IIFE nicht angegeben haben, was bedeutet, dass function (x) { ... }() unabhängig vom nachfolgenden () als Deklaration/Anweisung behandelt wird. Aber wenn Sie eine Funktion deklarieren, müssen Sie einen Namen angeben, weshalb die ( nach function unerwartet ist. Wenn Sie es als Ausdruck behandeln möchten, müssen Sie es in (...) umhüllen und verwenden Sie daher (function (x) { ... })().

Im zweiten Fall kann das Argument zu result.push(...) nur ein Ausdruck sein, also gibt es keine Zweideutigkeit, wie function (x) { ... }() zu interpretieren ist; es kann niemals eine Deklaration sein, und so muss es ein Ausdruck sein (entweder ein Funktions-Literal oder ein IIFE).

Als eine Analogie, denken Sie an function() { ... } wie die Zeichenfolge "hello".Sie können niemals "hello" isoliert verwenden; Der folgende Code ist nicht syntaktisch gültig:

var x = "foo"; 
"hello"; 

Dies ist im Wesentlichen, was Sie mit der anonymen Funktion tun:

var x = "foo"; 
function() { 
} 

Was ist mit dieser Funktion getan werden sollte? Es ist nichts zugewiesen, genau wie "hello" im früheren Beispiel ist nichts zugewiesen. Aber wir wissen, dass Funktionen aufgerufen werden können, also was wir mit (function() { ... }()) tun, heißt "nimm diese Funktion, die ich hier definiert habe, und nenne sie sofort". Es ist analog eine Methode auf einem Stringliteral des Aufrufs:

"abcd".substring(0, 2); // returns "ab" 

Und in der Tat, Sie etwas ähnliches mit einer Funktion tun konnten, was ich denke, ein wenig besser zeigt, was mit dem IIFE passiert:

// logs "hello" 
(function() { 
    console.log("hello"); 
}).call(); 

Die Klammern sind eine Möglichkeit, Mehrdeutigkeiten zu entfernen und dem Interpreter mitzuteilen, dass Sie die Funktion als Ausdruck/Literal anstelle einer Deklaration behandeln möchten. Wenn Sie im obigen Beispiel die umgebenden Klammern entfernen, erhalten Sie den gleichen Syntaxfehler für das unerwartete (.

+0

Ahhh. Das ist toll. Vielen Dank für die klare Erklärung. –

+0

@WilliamM. Froh, dass ich Helfen kann! –

+0

@VivinPaliath wurde für die Erkennung eines falschen IIFE-Aufrufs aktualisiert –

0

Im ersten Fall, Sie drängen Rückkehr Ihrer Funktionsdeklaration NICHT Aufruf, die

result.push(return function(){...})

Im zweiten Fall wirksam ist, Sie drängen die Rückkehr der Ausführung IIFE-Funktion, die Ihre zurück ursprüngliche Funktion, so dass ihr effektiv

result.push(function(){...})

Offensichtlich zweite ist das, was Sie wollen. Sie können zuerst zu

result.push(
    function() { 
     console.log(item + ' ' + list[x]); 
    }; 
); 

ändern, damit es funktioniert. No return während des Schiebens.

0

Es gab einen Syntaxfehler mit der Wrapper (IIFE) Funktion und falsch platziert Rückgabe Anweisung im ersten Fall. Hier ein fester (und leicht modifizierter) Snippet.

function buildList(list) { 
 
    var result = []; 
 
    for (var i = 0; i < list.length; i++) { 
 
      (function (x) { // this anonymous function declaration... 
 
       var item = 'item' + list[x]; 
 
       result.push(
 
        function() { 
 
         console.log(item + ' ' + list[x]); 
 
         return item + ' ' + list[x]; 
 
        } 
 
       ); 
 
      })(i);   // and simultaneous invocation... 
 
    } 
 
    return result; 
 
} 
 

 
buildList([1,2,3]).forEach(function(func) { 
 
    
 
    document.body.innerHTML += func() + '<br>'; 
 

 
});

Verwandte Themen