《Nodejs开发指南》for与forEach之间的差别
《Nodejs开发指南》for与forEach之间的差别
作者提到循环的陷阱
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
这个不难理解,作者建议改成这样,但是没有解释
files.forEach(function (filename) {
fs.readFile(filename,'utf-8',function (err,contents) {
console.log(filename+':'+contents);
})
})
我不懂,为什么把for改成forEach就解决问题了,for与forEach本质区别在哪里
《Nodejs开发指南》for与forEach之间的差别
问题背景
在Node.js中,你可能会遇到使用for
循环和Array.prototype.forEach()
处理异步操作时出现的不同结果。本文将详细解释这两种方法的区别,并提供相应的示例代码。
示例代码
首先来看一个使用for
循环的例子:
for (var i = 0; i < files.length; i++) {
fs.readFile(files[i], 'utf-8', function (err, contents) {
console.log(files[i] + ':' + contents);
});
}
这段代码的结果会输出一系列undefined
:
undefined:AAA
undefined:BBB
undefined:CCC
这是因为在回调函数执行时,i
的值已经变成了files.length
(即超出数组索引的值),所以files[i]
为undefined
。
使用 forEach
解决问题
接下来,我们看看使用forEach
的情况:
files.forEach(function (filename) {
fs.readFile(filename, 'utf-8', function (err, contents) {
console.log(filename + ':' + contents);
});
});
这段代码可以正确地输出文件内容:
AAA:...
BBB:...
CCC:...
原因分析
-
作用域问题:
- 在
for
循环中,变量i
是全局变量,在循环结束时它的值为files.length
。因此,当异步回调函数被执行时,i
的值已经是files.length
,导致files[i]
为undefined
。
- 在
-
闭包问题:
forEach
内部创建了一个新的作用域,每次迭代都会创建一个新的闭包,使得每次回调函数都能捕获到当前迭代的filename
值。因此,即使异步操作在循环结束后才完成,每个回调函数仍然能访问到正确的filename
。
-
性能考虑:
forEach
在内部实现上更简洁,但如果你需要提前终止循环,可能需要使用其他方法如some
或every
。
总结
for
循环:在处理异步操作时容易出错,因为循环变量的作用域和闭包问题可能导致意外的结果。forEach
:通过创建新的闭包来确保每次迭代都有独立的作用域,从而避免了上述问题。
通过上述分析,我们可以看到,使用forEach
能够更好地处理异步操作中的作用域问题,从而避免了输出undefined
的情况。
这是经典的js闭包问题,题主可自行查阅
forEach算是FP的半成品
for循环的时候i每次都是files.length所以找不到。 也可以这样改: 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); }
感谢,对闭包的理解又深了一步
也就是说forEach
不存在上下文环境这个问题?
使用js必然会遇见的闭包问题
for( var i = 0;i<files.length;i++){
fs.readFile(files[i],'utf-8',function (err,contents) {
//这一部分是异步执行的,其实差不多等到for循环完成才会执行,所以这时候的i==files.length ,懂了吗?
console.log(files[i] + ':' + contents);
})
}
顶一个,很好的知识点。
i 每次循环 复制一份就好啦
闭包啊
包装一层函数(闭包)会保持当前参数,so~