2010-10-21 2 views
1

Я работал довольно много с javascript, но вчера я начал использовать node.js. Это небольшой скрипт, который запускает jslint в файлах папки. В этом примере я изменил команду на вызов ls вместо jslint.Являются ли замыкания разными в node.js?

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?

ответ

13

Нет, они не отличаются друг от друга, это всего лишь самая распространенная ошибка с закрытием в JavaScript.

См., Вы находитесь в цикле, вы назначаете локальную переменную filename на каждой итерации цикла, поэтому вы фактически переопределяете ее значение. Так как это всегда одна и та же локальная переменная, и закрытие работает для ссылки, значение 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); 

Это делает всю работу вещь, несмотря на то, что это немного некрасиво. Вы можете, конечно, переместить это в именованную функцию, если вы не хотите загромождать свой внутренний цикл более анонимными функциями.

+0

Почему это на самом деле, что это заставляет пройти за значение? Я реализовал то же самое до прихода сюда, но пришел, чтобы понять, почему именно он работает по сравнению с наивной (проблемной) реализацией. – matanster

2

вы немного путаете код, в котором вы пишете этот

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]; 

может сделать его более ясным, где проблема. и почему, как и в предыдущем ответе, вам необходимо передать имя файла вашей функции.

Смежные вопросы