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议你需要传递文件名到你的函数。