Nodejs之循環與閉包

最近在邊學邊開發Nodejs,起初在代碼中大量使用for循環,review的時候感受很冗餘,便查了下nodejs中forEach方法,結果看到有網友提到nodejs關於循環的陷阱,回想本身在開發過程當中也曾遇到,只是當時沒有深究,如今再回顧思考下。node

http://cnodejs.org/topic/52e8e78a953654bb712654cb數組

循環陷阱閉包

for( var i = 0;i<files.length;i++){
    fs.readFile(files[i],'utf-8',function (err,contents) {
        console.log(files[i] + ':' + contents);
    })
}

輸出結果爲異步

undefined:AAA
undefined:BBB
undefined:CCC

輸出 undefined 是由於 fs.readFile是一個異步方法,它的回調在for循環執行完畢後纔開始執行, 而此時變量 i=files.length, 超出了邊界。函數

看到網友專業的回答是「閉包會把當前的環境保存下來,原來的代碼裏面那個 for 建立了若干個閉包,可是每一個閉包共享上下文環境 i。由於 for (很大可能)會先跑完,因此運行回調函數的時候 i 已經變成了 files.length,這時候 files[i] 由於超過數組邊界,因此就 undefined 了。」性能

解決這個問題的方式收集了下,目前有3種:學習

1. forEach測試

files.forEach(function (filename) {
    fs.readFile(filename,'utf-8',function (err,contents) {
        console.log(filename+':'+contents);
    })
})

不存在上下文關係,不過經過測試,forEach的性能比for差, 另外 forEach也是同步執行的spa

2. funcation factorycode

function gencb(filename) {
    return function (err, contents) {
        if (err) //...
        console.log(filename + ':' + contents);
    };
};

for( var i = 0;i<files.length;i++){
    fs.readFile(files[i],'utf-8', gencb(files[i]))
}

每次閉包都不相同。

3. 修改原代碼

for( var i = 0;i<files.length;i++){
(function(i){
fs.readFile(files[i],‘utf-8’,function (err,contents) {
console.log(files[i] + ‘:’ + contents);
});
})(i);
}

這種方式的名稱還不清楚,以後再學習學習。

 

關於 閉包

百度百科解釋:

閉包是指能夠包含自由(未綁定到特定對象)變量的代碼塊;這些變量不是在這個代碼塊內或者任何全局上下文中定義的,而是在定義代碼塊的環境中定義(局部變量)。「閉包」 一詞來源於如下二者的結合:要執行的代碼塊(因爲自由變量被包含在代碼塊中,這些自由變量以及它們引用的對象沒有被釋放)和爲自由變量提供綁定的計算環境(做用域)。

閉包的最簡單形式

function func(i)
{
  return function(){
    return i+1;
  }
}

其中 i 是函數func的一個局部變量,又被返回的匿名函數所使用。

這裏也只是大概瞭解了下,深刻學習: 

http://cnodejs.org/topic/567ed16eaacb6923221de48f

 

閉包的新理解:若是一個內部函數能夠訪問了它的外部變量,那麼它就是一個閉包。

 

閉包常常用於建立含有隱藏數據的函數(但並不老是這樣)。

var db = (function() {
// 建立一個隱藏的object, 這個object持有一些數據
// 從外部是不能訪問這個object的
var data = {};
// 建立一個函數, 這個函數提供一些訪問data的數據的方法
return function(key, val) {
    if (val === undefined) { return data[key] } // get
    else { return data[key] = val } // set
    }
// 咱們能夠調用這個匿名方法
// 返回這個內部函數,它是一個閉包
})();

db('x'); // 返回 undefined
db('x', 1); // 設置data['x']爲1
db('x'); // 返回 1
// 咱們不可能訪問data這個object自己
// 可是咱們能夠設置它的成員

該段引用自:http://kb.cnblogs.com/page/110782/

相關文章
相關標籤/搜索