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/

posted @ 2017-04-26 00:28  ohlucky  阅读(8918)  评论(0编辑  收藏  举报