Nodejs之循環與閉包


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

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也是同步執行的

2. funcation factory

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/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM