我有一个解析请求的formidable表单。然后这个请求就是正在上传的文件。在formidable中,如果有文件,你可以收听一个事件。
var form = new formidable.IncomingForm({
uploadDir: __dirname + '/temp',
keepExtensions: true
});
这是我将听取此事件的地方
form.on('file', function(name, file){
var file = file;
fs.readFile(file.path, readFileCallback);
});
function readFileCallback(err, contents){
console.log(file);
if (err) throw err;
....
}
我的第一个代码是一系列回调函数,它有点难以阅读和维护所以我用这种方法切换,我会声明函数然后将其称为回调,而不是像这样:
form.on('file', function(name, file){
fs.readFile(file.path, function(err, contents){
console.log(file);
if (err) throw err;
....
});
});
通过这种方法,我可以访问外部变量file
。我想知道两者在访问外部变量时有什么区别。提前谢谢。
答案 0 :(得分:1)
这是范围的问题。代码可以访问函数内声明的变量,它包含的函数(如果有的话),它包含的函数(如果有的话),等等,然后是全局变量。
在您的第一个示例中,readFileCallback
在form.on
回调之外宣布,因此它无法访问form.on
回调中的内容。
在你的第二个例子中,函数是里面的 form.on
回调,因此它可以访问其中的内容。
请注意,在第二个示例中,理论上每次调用回调时都会创建一个新函数。这很好,JavaScript引擎在创建函数时非常快(即使创建了单独的函数对象,优秀的代码也将重用代码。)
通常,您希望在最有可能访问所需内容的位置创建该功能。因此,在您的情况下,在 form.on
内,但在之外的readFile
回调。这正是你的第二个例子所在的地方。但是你可以使用像你的第一个例子那样的命名函数,只需将放在 form.on
的回调中:
form.on('file', function(name, file){
fs.readFile(file.path, readFileCallback);
function readFileCallback(err, contents){
console.log(file);
if (err) throw err;
....
}
});
让我们举一个例子,其中所有内容都有一个简单的名称,然后通过两个调用:
function outer(outerArg) {
function middle(middleArg) {
function inner(innerArg) {
console.log("innerArg = " + innerArg);
console.log("middleArg = " + middleArg);
console.log("outerArg = " + outerArg);
}
inner(middleArg.toLowerCase());
}
middle(outerArg.toUpperCase());
}
outer
包含middle
,其中包含inner
和outer
来电middle
(以及middle
来电inner
)。电话:
outer("Test1");
outer
获取了arg "Test1"
middle
"TEST1"
inner
"test1"
inner
输出:
innerArg = test1 middleArg = TEST1 outerArg = Test1
到目前为止,这么简单,但它比这更令人兴奋:如果middle
返回一个调用inner
的函数,而不是立即调用它,outer
该怎么办?返回返回middle
&#39}的返回值?
function outer(outerArg) {
function middle(middleArg) {
function inner(innerArg) {
console.log("innerArg = " + innerArg);
console.log("middleArg = " + middleArg);
console.log("outerArg = " + outerArg);
}
function caller() { // ***
inner(middleArg.toLowerCase()); // ***
} // ***
return caller; // ***
}
return middle(outerArg.toUpperCase()); // ***
}
现在,调用outer
根本没有任何输出:
var f = outer("Test2");
然后调用函数middle
返回(caller
):
f();
输出:
innerArg = test2 middleArg = TEST2 outerArg = Test2
在outer
和middle
返回后,参数仍然存在!但它更有趣:
var f1 = outer("Test3");
var f2 = outer("Test4");
f2(); // Note -- calling the second one first
f1();
输出:
innerArg = test4 middleArg = TEST4 outerArg = Test4 innerArg = test3 middleArg = TEST3 outerArg = Test3
这意味着,在对outerArg
的两次调用完成后,两个 outer
仍然存在,以及两个 middleArgs
。怎么样?
它们存在于附加到函数的对象上:
outer
会创建一个执行上下文(一个对象),除其他外(并留下很多细节)保存该调用的参数和局部变量{{ 1}}。我们称之为"外部背景。"它还引用了包含它的执行上下文(我们的代码中的全局上下文)。通常,当一个功能返回时,该对象会被清理...... outer
创建了一个函数outer
。创建函数时,当前执行上下文将附加到函数。这就是它如何在外部环境中访问变量等。middle
调用outer
,创建内部执行上下文,middle
创建另外两个函数(middle
和inner
),每个函数都得到内部与他们相关的背景。 caller
然后返回 middle
,因此在caller
调用完成后,caller
存在。由于middle
具有对内部执行上下文的引用,因此即使caller
已返回,上下文仍然存在(就像任何其他对象一样)。由于该上下文引用middle
,inner
也继续存在。inner
返回outer
的返回值(middle
),这意味着caller
返回时仍然存在caller
,这意味着它引用的内部上下文仍然存在,这意味着outer
仍然存在,和外部上下文仍然存在,因为内部上下文具有对它的引用。 ... inner
和f1
在f2
返回后访问这些参数的方式是:当您运行它们时,它们会查找附加到它们的上下文中的值。