node.js 中的闭包有啥不同吗?

Posted

技术标签:

【中文标题】node.js 中的闭包有啥不同吗?【英文标题】:Are closures different in node.js?node.js 中的闭包有什么不同吗? 【发布时间】:2011-04-28 15:40:38 【问题描述】:

我在 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

当文件名显然应该与ls 的结果匹配时,为什么console.log(filename + " : " + stdout); 行总是打印jskata.nofreeze.js? node.js 中的闭包和作用域与 javascript 中的不同吗?

【问题讨论】:

【参考方案1】:

你写这个的地方有点混乱

for (var i = 0; i < files.length; i++) 
    var filename = files[i];

因为 javascript 中的变量只有函数级别的作用域,所以每次循环都会重用文件名变量。

把代码写到这里:

var filename;
for (var i = 0; i < files.length; i++) 
    filename = files[i];

可能会更清楚问题出在哪里。以及为什么前面的答案表明您需要将文件名传递给您的函数。

【讨论】:

【参考方案2】:

不,它们并没有什么不同,这只是 JavaScript 中最常见的闭包陷阱。

你看,你在一个循环中,你在循环的每次迭代中都分配了局部变量filename,因此你实际上覆盖了它的值。由于它始终是同一个局部变量,并且闭包对每个引用起作用,因此回调内部的 filename 的值在循环的每次迭代中都会得到更新。

'jskata.nofreeze.js' 恰好是目录中的最后一个文件,因此它也是分配给filename 的最后一个值。

要解决它,您需要传递filename per 值的值:

// Run jslint on each file
(function(c, f) 
    cp.exec("cat " + c, function(error, stdout, stderr) 
      console.log(f + " : " + stdout);
    );
)(complete, filename);

这使得整个事情都能正常工作,尽管它有点难看。如果您不想让更多匿名函数使内部循环混乱,您当然可以将其移出到命名函数中。

【讨论】:

为什么实际上,这会强制按值传递?在来这里之前,我已经实现了相同的功能,但后来我想知道为什么它与天真的(问题)实现相比确实有效。

以上是关于node.js 中的闭包有啥不同吗?的主要内容,如果未能解决你的问题,请参考以下文章

对 Node.js 的 xml 到 json 有啥建议吗?

为啥 Node.js 的 Mysql Native 驱动程序的查询执行时间如此之长?有啥选择吗?

Node.js 开头有啥意义? [关闭]

jQuery 和 Node.js 有啥区别? [关闭]

node.js 中的 __dirname 和 ./ 有啥区别?

node.js 中的 module.parent 有啥用?如何引用 require()ing 模块?