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 的 Mysql Native 驱动程序的查询执行时间如此之长?有啥选择吗?