Node.js 中的闭包有何不同?
我经常使用 javascript,但昨天,我开始使用 Node.js。这是一个在文件夹的文件上运行 jslint 的小脚本。对于此示例,我将命令更改为调用 ls
而不是 jslint
。
var sys = require("sys");
var fs = require("fs");
var cp = require('child_process');
var path = fs.realpathSync("./src/");
fs.readdir(fs.realpathSync("./src/"), function(err, files) {
for (var i = 0; i < files.length; i++) {
var filename = files[i];
var complete = path + filename;
// Run jslint on each file
var jslint = cp.exec("ls " + complete, function(error, stdout, stderr) {
console.log(filename + " : " + stdout);
});
}
});
输出是这样的:
jskata.nofreeze.js : /home/dan/php/jskata/src/jskata.undo.js
jskata.nofreeze.js :/home/dan/php/jskata/src/jskata.nofreeze.js
jskata.nofreeze.js :/home/dan/php/jskata/src/jskata.timezone.js
为什么 console.log(filename + " : " + stdout);
行总是打印 jskata.nofreeze.js
文件名何时应该明显匹配 ls 的结果? Node.js 中的闭包和作用域与 javascript 中的闭包和作用域不同吗?
I have worked quite a lot with javascript but yesterday, I started using node.js. It's a little script that runs jslint on the files of a folder. For this example, I changed the command to call ls
instead of jslint
.
var sys = require("sys");
var fs = require("fs");
var cp = require('child_process');
var path = fs.realpathSync("./src/");
fs.readdir(fs.realpathSync("./src/"), function(err, files) {
for (var i = 0; i < files.length; i++) {
var filename = files[i];
var complete = path + filename;
// Run jslint on each file
var jslint = cp.exec("ls " + complete, function(error, stdout, stderr) {
console.log(filename + " : " + stdout);
});
}
});
The output is this :
jskata.nofreeze.js : /home/dan/php/jskata/src/jskata.undo.js
jskata.nofreeze.js : /home/dan/php/jskata/src/jskata.nofreeze.js
jskata.nofreeze.js : /home/dan/php/jskata/src/jskata.timezone.js
Why do the line console.log(filename + " : " + stdout);
always prints jskata.nofreeze.js
when the filename should obviously match the result of the ls
? Are closures and scopes different in node.js than in javascript?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不,它们没有任何不同,这只是 JavaScript 中闭包最常见的陷阱。
看,你在一个循环中,你在循环的每次迭代中分配局部变量
filename
,因此你实际上覆盖了它的值。由于它始终是相同的局部变量,并且闭包按引用工作,因此回调内的filename
值会在循环的每次迭代中获得更新。“jskata.nofreeze.js”恰好是目录中的最后一个文件,因此它也是分配给
filename
的最后一个值。要解决这个问题,您需要传递
filename
per 值:这使得整个事情正常工作,尽管它有点难看。如果您不想让更多的匿名函数扰乱内部循环,您当然可以将其移至命名函数中。
No they aren't any different, this is just the most common pitfall with closures in JavaScript.
See, you're in a loop, you're assigning the local variable
filename
on every iteration of the loop, therefore you're in fact overriding it's value. Since it's always the same local variable, and the closure works per reference, the value offilename
inside the callback gets updates on each iteration of the loop.'jskata.nofreeze.js' just happens to be the last file in the directory and therefore it's also the last value that gets assigned to
filename
.To solve it you need to pass the value of
filename
per value:This makes the whole thing work, even though it's a bit ugly. You can of course move this out into a named function if you don't want to clutter your inner loop with more anonymous functions.
编写此代码的代码有点令人困惑
,因为 javascript 中的变量仅具有函数级别的范围,因此每次循环时都会重用 filename 变量。
将代码写入此:
可能会更清楚问题出在哪里。以及为什么正如前面的答案所示,您需要将文件名传递给您的函数。
you have slightly confusing code where you write this
because variables in javascript only have scope a the function level, so the filename variable is reused each time around the loop.
writing the code to this:
might make it clearer where the problem is. and why as the previous answer suggests you need to pass filename to your function.