2014-05-18 38 views
1

我在面試過程中被問到了下面的問題,但我仍然無法理解它,所以我想徵求您的意見。Javascript關閉和自動執行匿名功能

這裏的問題:

var countFunctions = []; 
for(var i = 0; i < 3; i++){ 
    countFunctions[i] = function() { 
    document.getElementById('someId').innerHTML = 'count' + i; 
    }; 
} 
//The below are executed in turns: 
countFunctions[0](); 
countFunctions[1](); 
countFunctions[2](); 

當被問及什麼是上面的輸出,我分別COUNT0,COUNT1和COUNT2說。很明顯,答案是錯誤的,並且輸出應該都是count3,因爲關閉的概念(當時我並不知道)。於是我通過this article去,並意識到,我應該使用閉合,使這項工作,如:

var countFunctions = []; 
function setInner(i) { 
    return function(){ 
    document.getElementById('someId').innerHTML = 'count' + i; 
    }; 
} 
for(var i = 0; i < 3; i++){ 
    countFunctions[i] = setInner(i); 
} 
//Now the output is what was intended: 
countFunctions[0]();//count0 
countFunctions[1]();//count1 
countFunctions[2]();//count2 

現在,這一切都很好,但我記得面試官用簡單的東西,使用自動執行功能類似這樣的:

var countFunctions = []; 
for(var i = 0; i < 3; i++) { 
    countFunctions[i] = (function(){ 
    document.getElementById('someId').innerHTML = 'count' + i; 
    })(i); 
} 

我明白上面的代碼的方式,我們跳過一個單獨的函數的聲明和簡單的調用和執行在函數中的for循環。

但是,當我跑瞭如下:

countFunctions[0]; 
countFunctions[1]; 
countFunctions[2]; 

它沒有工作,與被卡在COUNT2所有的輸出。

所以我試着做以下代替:

for(var i = 0; i < 3; i++) { 
    countFunctions[i] = function(){ 
    document.getElementById('someId').innerHTML = 'count' + i; 
    }; 
} 

,然後運行countFunctions[0]()countFunctions[1]()countFunctions[2](),但沒有奏效。輸出現在被卡在count3。

現在我真的不明白。我只是使用與setInner()相同的代碼行。所以我不明白爲什麼這不起作用。事實上,我可以堅持setInner類型的代碼結構,它可以工作,而且更全面。但是我很想知道面試官是如何做到的,以便更好地理解這個話題。

+0

不幸的是,這似乎並沒有成爲解決辦法:http://jsfiddle.net/Kt2Xa/ – anthonytwp

回答

1

相關文章讀到這裏是JavaScript closure inside loops – simple practical examplehttp://benalman.com/news/2010/11/immediately-invoked-function-expression/(儘管你似乎已經明白IEFEs很好 - 就像你說的,他們是「跳過一個單獨的函數的聲明和簡單地調用和執行功能」 )。

什麼你沒有注意到的是,setInner呢,叫的時候,return關閉功能:

function setInner(i) { 
    return function() { 
     document.getElementById('someId').innerHTML = 'count' + i; 
    }; 
} 

// then do 
var countFunction = setInner("N"); // get the function 
countFunction(); // call it to assign the innerHTML 

所以,如果你把它翻譯成IEFE,你仍然需要創建(和返回)這實際上將獲得分配給countFunctions[i]功能:現在

var countFunctions = []; 
for(var i = 0; i < 3; i++) { 
    countFunctions[i] = (function(i){ 
     return function() { 
      document.getElementById('someId').innerHTML = 'count' + i; 
     }; 
    })(i); 
} 

typeof countFunctions[0]"function",不"undefined"在你r代碼,你可以實際上他們打電話

+0

你好,非常感謝您的反饋意見。我試過你的方法,所以countFunctions [0]現在是一個函數,可以調用。然而,問題在於,「我」似乎陷入了3,因此不管我稱之爲「函數函數」[0],callFunctions [1]還是callFunctions [2],結果仍然是count3。請參閱http://jsfiddle.net/r5Nnp/ – anthonytwp

+0

感謝提示,我已經忘記了IEFE的參數,因此沒有構建閉包...請參閱編輯。 – Bergi

0

看看這四個功能:

var argument = 'G';      //global 

function passArgument(argument){ 
    alert(argument);      //local 
} 

function noArguments(){ 
    alert(argument);      //global 
} 

function createClosure_1(argument){ 
    return function(){ 
       alert(argument);   //local 
      }; 
} 

function createClosure_2(argument){ 
    var argument = argument;    //local 
    return function(){ 
       alert(argument);   //local 
      }; 
} 

passArgument('L');      //L 
noArguments();       //G 
createClosure_1('L')      //L 
createClosure_2('L')      //L 
alert(argument)       //G 
  1. 我認爲,第一個功能是顯而易見的。
  2. 在函數noArguments中引用全局參數值;
  3. 第三和第四個功能做同樣的事情。它們創建一個本地變量,它不會在它們內部改變,並返回一個引用該局部變量的函數。

    因此,你的問題的第一個和最後一個代碼片段是創建許多函數,如引用全局變量i的noArguments, 。

    在第二個片段中,您的setInner像createClosure_1一樣工作。在你的循環中你創建了三個閉包,三個局部變量。當你在countFunctions中調用函數時,它們會獲得在創建閉包時創建的局部變量的值。

    在第三個函數中,您將這些函數的執行結果賦值給數組元素,這些數組元素是未定義的,因爲它們不會從該函數返回任何內容。