Node.js 中的闭包有何不同?

发布于 2024-09-28 14:59:06 字数 1039 浏览 2 评论 0原文

我经常使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

被你宠の有点坏 2024-10-05 14:59:06

不,它们没有任何不同,这只是 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);

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

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 of filename 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:

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

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.

谈场末日恋爱 2024-10-05 14:59:06

编写此代码的代码有点令人困惑

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

,因为 javascript 中的变量仅具有函数级别的范围,因此每次循环时都会重用 filename 变量。

将代码写入此:

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

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

you have slightly confusing code where you write this

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

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:

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

might make it clearer where the problem is. and why as the previous answer suggests you need to pass filename to your function.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文