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中的不同?
不,它们没有什么不同,这只是JavaScript中最常见的封闭陷阱。
看,你在一个循环中,你在循环的每一次迭代中分配局部variablesfilename
,因此你实际上覆盖了它的值。 由于它始终是相同的局部variables,并且闭包对每个引用都起作用,所以在callback中的filename
的值将在循环的每次迭代中得到更新。
'jskata.nofreeze.js'恰好是目录中的最后一个文件,因此它也是分配给filename
的最后一个值。
要解决它,你需要传递每个值的filename
值:
// Run jslint on each file (function(c, f) { cp.exec("cat " + c, function(error, stdout, stderr) { console.log(f + " : " + stdout); }); })(complete, filename);
这使整个事情工作,即使它有点丑陋。 如果你不想用更多的匿名函数来混乱你的内部循环,你当然可以把它移动到一个命名的函数中。
你在写这个的时候会有些混乱的代码
for (var i = 0; i < files.length; i++) { var filename = files[i];
因为JavaScript中的variables只具有函数级别的范围,所以文件名variables在循环中每次都被重用。
编写代码到这个:
var filename; for (var i = 0; i < files.length; i++) { filename = files[i];
可能会使问题更清楚。 为什么以前的答案build议你需要传递文件名到你的函数。