2015-12-27 2 views
0

Я довольно новичок в JavaScript, и я изучаю следующие темы: замыкание и IIFE (Выражение функции с немедленным вызовом).Как именно работает эта функция JavaScript IIFE?

Так что я следующий пример, связанный с закрытия концепции, очень комментирует:

/* Classical example as far as why closure can make your code look hard to anticipate, but understanding how works is "simple" 
*/ 

function buildFunctions() { 

    var arr = [];      // Create an empty array 

    for (var i = 0; i < 3; i++) {  

     /* Add a new function to this array, identical functions but are 3 differents functions: 
     */ 
     arr.push(
      function() {   // It is not invoking the function, it is just creating it 
       console.log(i); // i= 0, 1, 2 
      } 
     ) 

    } 

    return arr; 
} 

var fs = buildFunctions();  // Call the build() function that put the 3 functions inside the array 


/* When these functions are actually invoked and it looks at the 'i' variable they use the OUTER REFERENCE inside their execution context. So what will be the values? You might expect that the values will be 0, 1, 2 but this is wrong because at the end of the for loop inside the buildFunctions() function the value of the 'i' variable is 3. So when the anonymous functions inside the arrays are invoked they use the OUTER REFERENCE and the CLOSURE CONCEPT to access to the memory space related to the popped of fbuildFunctions() function that contain the variables of this function, and here the 'i' value is 3 !!! 

N.B: Many people think that the result should be 0,1,2 because they think that when the function is pushed into the array it is invoked but it is not !!! The function is invoked here: 
*/ 
fs[0]();  // Invoke the first function inside the array, the value is 3 
fs[1]();  // Invoke the second function inside the array, the value is 3 
fs[2]();  // Invoke the third function inside the array, the value is 3 


/* What have I to do if I want this works? (I want that the first function return 0, the second return 1 and the third return 3). 
In order to preserve the value of 'i' for the inner anonymous function I am going to need a separate execution context for each of the functions that I am pushing into the array. I need a parent scope that holds the current values of 'i' variable as the loop goes on. So, the only way to get an execution context is to execute a function. To execute a function on the fly I use IIFE concept. 

In this way every time that the loop runs, differently from the previous example, the anonymous inner function is executed passing to it the current value of the 'i' variable. This value is so stored in the 'j' variable in the execution context of the current performed anonymous inner function. 
So at first time pass 0, at the second time pass 1, at the third time pass 3 and these 3 values are stored in the 'j' variable of the related execution context. 
*/ 
function buildFunctions2() { 

    var arr = [];       // Create an empty array 

    for (var i = 0; i < 3; i++) { 
     arr.push(
      (function(j) {     
       return function() { 
        console.log(j);   // print the current value 
       } 
      }(i))   // I use IIFE concept to invoke the function passing the current value of the 'i' variable 
     ) 

    } 

    return arr; 
} 

var fs2 = buildFunctions2(); // Call th build() function that put the 3 functions inside the array 

/* 
When these functions are performed don't use closure concept because it have not to use the outer reference but use the 'j' value inside the current function execution context. 
*/ 
fs2[0](); 
fs2[1](); 
fs2[2](); 

меня совершенно ясно, как закрытия работает, но у меня есть некоторые сомнения по поводу второго примера предыдущий пример, связанный с функцией buildFunctions2().

Так первый пример показывает концепцию закрытия и тот факт, что после внешней ссылки каждых выполняемых функций программы достигает объем памяти, связанный с переменным из buildFunctions() также, если его контекст выполнения было выскочил из контекстного стека выполнения. Таким образом, результат будет всегда одинаковым для всех трех функций, и это будет 3.

Это совершенно ясно для меня.

Второй пример предназначен для получения значений 0, 1 и 3 при выполнении 3 функций, помещенных внутри массива.

Для получения этого поведение по buildFunctions2() выполнить цикл, которые помещают функцию внутри текущего элемента массива, используя концепцию IIFE, на самом деле:

for (var i = 0; i < 3; i++) { 
    arr.push(
     (function(j) {     
      return function() { 
       console.log(j);   // print the current value 
      } 
     }(i))   // I use IIFE concept to invoke the function passing the current value of the 'i' variable 
    ) 

} 

То, от чего Я понимаю, это означает, что каждый раз, когда они вводятся в цикл for, в массив добавляется новая анонимная функция и выполняется передача в нее параметра «i» как параметра. Таким образом, я не использую концепцию закрытия, потому что никакие мои функции не печатают значения 'j', которые находятся в контексте этих анонимных функций. Правильно ли это мое рассуждение?

Дело в том, что я не могу понять: если функция добавляется в массив и выполняется, почему у меня также добавить:

fs2[0](); 
fs2[1](); 
fs2[2](); 

, чтобы получить результат в консоли FireBug? Если я удалю эти 3 строки, которые вызывают функцию, связанную со всеми элементами моего массива, я не получаю никакого результата. Мне кажется странным, потому что из того, что я понял, используя IIFE, я добавляю функцию к массиву, и я автоматически выполняю его, передавая ему текущее значение «i» (то есть 0,1,2) так почему же после этого я должен явно выполнять функции?

Что мне не хватает?

+1

Это «закрытие», а не «кло * и * уверен». Google довольно прощает опечатки вроде этого, но не все поиски, поэтому вы можете найти больше, если вы наберете его правильно. – GolezTrol

+1

IIFE - это вызов функции, а функция, которую вы называете самим **, возвращает другую функцию **. Это возвращаемые функции, которые вы должны вызывать с помощью 'fs2 [0]()' и т. Д. – Pointy

+0

@GolezTrol Я знаю, что тема связана с концепцией clousure, но если вы читаете мой вопрос, это другое, и это больше связано с сомнением IIFE – AndreaNobili

ответ

3

Если вы посмотрите на эту часть кода:

(function(j) {     
     return function() { 
      console.log(j); 
     } 
    }(i)) 

Вы заметите, что есть два function s. Внешний - это IIFE и будет выполняться сразу же после выполнения этой части кода.

Этот внешний function определяет другой function (внутренний), который использует значение j, которое является локальным для внешней функции (передается как параметр). Однако этот function не выполнен (как в первом примере) и только что вернулся, который будет выполнен позже, когда вы запустите fs2[0]().

Примеры различались определения и исполнения:

function fn1(a) { } // defines a function named fn1, does not execute it 

fn1(123); // executes the function defined above 

fn2 = function(a) { } // defines an anonymous function, does not execute it, then stores it in fn2 

fn2(234); // executes the function defined above 

(function(a) { })(345); // defines an anonymous function, and executes it right away: that's an IIFE 
+0

Ahhhh ok, поэтому, исправьте меня, если я я делаю неправильное утверждение, выполняемая функция является внешней, которая содержит текущее значение «j» в контексте выполнения в стеке. Затем, когда анонимная внутренняя выполняется явно, внешний контекст выталкивается из стека, но внутренний может получить доступ к своей переменной «j», используя концепцию clousure, верно ли это из моих рассуждений? – AndreaNobili

+1

Да, это правильно. Но опять же, это ** закрытие ** (нет «u»), а не _clousure_ – jcaron

Смежные вопросы