2014-12-08 54 views
0

我正在閱讀這個tutualial javascriptissexy.com.我跟着直到最後一個例子。關於封閉和內部的一些問題IIFE

function celebrityIDCreator (theCelebrities) { 
    var i; 
    var uniqueID = 100; 
    for (i = 0; i < theCelebrities.length; i++) { 
     theCelebrities[i]["id"] = function (j) { // the j parametric variable is the i passed in on invocation of this IIFE 
      return function() { 
       return uniqueID + j; // each iteration of the for loop passes the current value of i into this IIFE and it saves the correct value to the array 
      }(); // BY adding() at the end of this function, we are executing it immediately and returning just the value of uniqueID + j, instead of returning a function. 
     } (i); // immediately invoke the function passing the i variable as a parameter 
    } 

    return theCelebrities; 
} 

var actionCelebs = [{name:"Stallone", id:0}, {name:"Cruise", id:0}, {name:"Willis", id:0}]; 

var createIdForActionCelebs = celebrityIDCreator (actionCelebs); 

var stalloneID = createIdForActionCelebs [0]; 
console.log(stalloneID.id); // 100 

var cruiseID = createIdForActionCelebs [1]; 
console.log(cruiseID.id); // 101 

首先,我沒有看到一個IIFE,或者至少在語法我很熟悉,其中有將與領先的左側括號一個(function()...。另外,

return function() { 
    return uniqueID + j; // each iteration of the for loop passes the current value of i into this IIFE and it saves the correct value to the array 
    }(); 

爲什麼這兩個returns?如果這意味着一個IIFE不需要周圍的括號?另外,j如何在i前面的例子中立即增加到數組長度?關於訪問actionCelebs參數的元素id的行theCelebrities[i]["id"] = function (j) {。爲什麼該屬性最初需要設置爲每個元素的0

先前的例子

// This example is explained in detail below (just after this code box).​ 
function celebrityIDCreator (theCelebrities) { 
    var i; 
    var uniqueID = 100; 
    for (i = 0; i < theCelebrities.length; i++) { 
     theCelebrities[i]["id"] = function() { 
     return uniqueID + i; 
     } 
    } 

    return theCelebrities; 
} 

var actionCelebs = [{name:"Stallone", id:0}, {name:"Cruise", id:0}, {name:"Willis", id:0}]; 

var createIdForActionCelebs = celebrityIDCreator (actionCelebs); 

var stalloneID = createIdForActionCelebs [0]; 
console.log(stalloneID.id()); // 103  

值的這裏,所有都設置爲103

+0

「前面的例子」的問題是分配給id字段的函數是celebrityIDCreator函數中引用「i」的閉包。這就是爲什麼所有明星都會得到相同的ID。頂部的例子是正確的方法。它定義了一個工廠方法,它爲不同的名人返回不同的功能並執行分配ID的功能。 – nhahtdh 2014-12-08 04:54:09

+0

你不需要如圖所示的循環中的內部函數,這是浪費代碼,性能和可讀性,什麼都不做。註釋掉內在的一切,一切工作都一樣。 – dandavis 2014-12-08 05:37:13

+0

@dandavis你的意思是說這個'return函數(){return {0}返回uniqueID + j; // for循環的每次迭代都會將當前值i傳遞給此IIFE,並將正確的值保存到數組中 }();'可以變成簡單的'return uniqueID + j;'?謝謝參觀。 – 1252748 2014-12-08 05:53:43

回答

2

問題的答案:

  1. IIFE代表立即調用函數表達式。在JavaScript中,函數文字以兩種形式之一出現:(1)全功能定義語句或(2)表達式。全功能定義語句具有function作爲語句的主標記,這意味着語句不是表達式,而只是一個函數定義。它有效地導致在當前範圍內創建一個本地(或全局範圍內的全局範圍)變量,其名稱等於函數定義語句中給出的函數名稱,並且該值等於對該函數的引用:

    function myFunction() {} 
    myFunction(); 
    

function任何位置發生(作爲第一令牌)的表達式內,函數定義被說成是「expressionized」並執行自動創建任何局部變量,但可以存儲在一個變量中通過賦值給它,或者立即通過一對括號跟在它之後調用它:

var func = function() { return 7; }; 
alert(func()); // 7 
var funcRes = function() { return 3; }(); 
alert(funcRes); // 3 

嚴格地說,術語IIFE可以指任何上下文其中函數定義expressionized,然後立即通過一對括號的下列它調用。你可以在你的代碼示例中看到,它們使用返回uniqueID + j的函數執行此操作,並且它們還使用包含所述函數的函數執行此操作,並簡單地將其返回值中繼到它的父範圍,因此兩者都符合IIFE。

在我的經驗中,術語IIFE是最常用的指代包括整個語句的IIFE,因而左括號是必要的exressionize函數定義,例如:

(function() { 
    var localVar = 3; 
    alert(localVar); 
})(); 

我認爲這就是爲什麼你發現代碼示例有點意外。但是,根據IIFE的嚴格定義,代碼示例中的這兩個函數定義都可以作爲IIFE使用;只要function關鍵字不是作爲語句中的第一個標記出現,那麼它將被表達,並且可以立即被調用以形成IIFE。

  1. 這兩個return s作爲代碼設計的一部分是非常必要的。不可否認,整個事情是非常人爲的,並且有一個更簡單的方法來完成任務,即一個簡單的循環遍歷數組,並將id散列鍵的值賦予從uniqueID增加的數字,我想,試着展示IIFE。內部返回表達式計算uniqueIDj中的下一個id值,它們都由內部函數關閉,並從內部IIFE返回,然後外部返回繼電器從外部IIFE返回值返回到celebrityIDCreator函數範圍,在哪裏可以分配。

  2. 不,IIFE不需要圍繞圓括號。爲了表達一個函數,所有需要的是function關鍵字而不是作爲該語句的第一個標記出現。

  3. closuring的完整過程如下:當定義了一個函數,幷包含一個變量,其標識符不結合任何本地變量(以var或函數參數聲明的變量),那麼它封閉物圍繞最接近祖先(考慮解析樹)本地具有相同的標識符,或全局如果它不能綁定到任何祖先的本地。重要的一點是:這是一個可變參考文件,它被封閉文件捕獲,不是 a 變量值

在「先前的例子」當地i是住在celebrityIDCreator功能範圍周圍i關閉。重要的是,該函數立即調用而不是,但函數的引用存儲爲散列鍵的實際值id。稍後在打印期間調用它。這意味着當函數最後被調用時,變量i已經完成循環數組,並且現在保留其最終值103.如果該函數被立即調用,那麼i實際上將在循環期間被評估,並且它將解析爲其當前值,這將是正確的遞增值。

在您的主代碼示例中,內部IIFE中的j正在關閉外部IIFE的函數參數,這是臨時的,並且不會增加;該參數j是一個與i中的celebrityIDCreator函數作用域不同的變量,該函數作用域永遠不會關閉。此外,內部IIFE正在被立即調用,因此無論如何它都會解析爲變量的當前值。所以他們在這裏實際上已經過分了;爲什麼最終分配值是正確的遞增值而不是最大值(103)有兩個原因。

要點:閉合關閉變量周圍,而不是值。

  1. id property最初不需要設置爲0;看起來只是一個佔位符。當它被分配在celebrityIDCreator中時,它被覆蓋(在你的主例子和「前面的例子」中)。由於在前面的例子中,它不是被另一個數字覆蓋,而是被一個函數覆蓋,這有點奇怪。再次,整個事情是有點人爲的(作者沒有冒犯......),但所有的概念都在那裏。