Javascript:如何在回调函数中访问局部变量?

时间:2022-05-12 19:55:31

I have a formidable form which parse the request. Then along with this request is the file being uploaded.. In formidable you can listen to an event if there's a file.

我有一个强大的形式来解析请求。然后这个请求就是正在上传的文件。如果有文件,你可以收听一个事件。

var form = new formidable.IncomingForm({
    uploadDir: __dirname + '/temp',
    keepExtensions: true
});

This is where I will listen to the event

这是我将听取此事件的地方

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;
  ....
}

My first code was a chain of callback functions and it's kind of hard to read and maintain so I switch with this approach where I would declare functions then call it as a callback instead of like this:

我的第一个代码是一系列回调函数,它有点难以阅读和维护所以我用这种方法切换,我会声明函数然后将其称为回调,而不是像这样:

form.on('file', function(name, file){
   fs.readFile(file.path, function(err, contents){
      console.log(file);
      if (err) throw err;
      .... 
  });
});

With this kind of approach, I could access the outside variable which is file. I'm wondering what is the difference between the two in accessing the outside variables. Thanks in advance.

通过这种方法,我可以访问外部变量fi​​le。我想知道两者在访问外部变量时有什么区别。提前致谢。

1 个解决方案

#1


1  

It's a matter of scope. Code has access to the variables declared within the function, its containing function (if any), its containing function (if any), and so on, and then globals.

这是一个范围问题。代码可以访问函数内声明的变量,它包含的函数(如果有的话),它包含的函数(如果有的话),等等,然后是全局变量。

In your first example, readFileCallback is declared outside the form.on callback, and so it doesn't have access to things inside the form.on callback.

在第一个示例中,readFileCallback在form.on回调之外声明,因此它无法访问form.on回调中的内容。

In your second example, the function is inside the form.on callback, and so it does have access to the things inside it.

在第二个示例中,函数位于form.on回调中,因此它可以访问其中的内容。

Note that in the second example, in theory a new function is created each time the callback is called. That's fine, JavaScript engines are really fast at creating functions (and good ones will reuse the code even though a separate function object is created).

请注意,在第二个示例中,理论上每次调用回调时都会创建一个新函数。没关系,JavaScript引擎在创建函数方面非常快(即使创建了单独的函数对象,优秀的函数也会重用代码)。

Normally you want to create the function at the outermost location where it has access to everything it needs. So in your case, that would be inside form.on, but outside the readFile callback. Which is exactly where your second example has it. But you can use a named function like your first example if you like, just put it in form.on's callback:

通常,您希望在最外面的位置创建该功能,以便能够访问所需的一切。所以在你的情况下,这将在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;
      .... 
   }
});

Let's take an example where everything had a simple name, and follow through two calls:

让我们举一个例子,其中一切都有一个简单的名称,并通过两个调用:

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 contains middle which contains inner, and outer calls middle (and middle calls inner). A call:

outer包含中间,包含内部和外部调用中间(和中间调用内部)。一个电话:

outer("Test1");
  1. outer gets the arg "Test1"
  2. 外部获取arg“Test1”

  3. It calls middle with "TEST1"
  4. 它用“TEST1”调用中间

  5. It calls inner with "test1"
  6. 它用“test1”调用内部

  7. inner outputs:

    innerArg = test1
    middleArg = TEST1
    outerArg = Test1
    
  8. 内在输出: innerArg = test1 middleArg = TEST1 outerArg = Test1

So far, so simple, but it's more exciting than that: What if middle returns a function that calls inner, instead of calling it immediately, and outer returns returns middle's return value?

到目前为止,这么简单,但它比那更令人兴奋:如果中间返回一个调用内部的函数,而不是立即调用它,外部返回返回中间的返回值,该怎么办?

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());          // ***
}

Now, calling outer doesn't have any output at all:

现在,调用outer根本没有任何输出:

var f = outer("Test2");

But then calling the function middle returned (caller) does:

但后来调用函数middle返回(调用者):

f();

Output:

innerArg = test2
middleArg = TEST2
outerArg = Test2

The arguments still exist after outer and middle return! But it's even more interesting:

外部和中间回归后,这些论点仍然存在!但它更有趣:

var f1 = outer("Test3");
var f2 = outer("Test4");
f2();  // Note -- calling the second one first
f1();

Output:

innerArg = test4
middleArg = TEST4
outerArg = Test4
innerArg = test3
middleArg = TEST3
outerArg = Test3

So that means, two outerArgs still existed after both calls to outer had finished, along with two middleArgs. How?

这意味着,在两个外部调用完成后,两个outerArgs仍然存在,还有两个middleArgs。怎么样?

They exist on objects attached to the functions:

它们存在于附加到函数的对象上:

  • Calling outer creates an execution context (an object), which amongst other things (and leaving out a lot of details) holds the arguments and local variables for that call to outer. Let's call it the "outer context." It also has a reference to the execution context containing it (the global context, in our code). Normally that object gets cleaned up when a functon returns...
  • 调用外部会创建一个执行上下文(一个对象),除其他外(并省略很多细节)保存该外部调用的参数和局部变量。我们称之为“外部背景”。它还引用了包含它的执行上下文(我们的代码中的全局上下文)。通常,当一个功能返回时,该对象会被清理掉...

  • ...but outer creates a function, middle. When you create a function, the current execution context is attached to the function. That's how it has access to the variables and such in that outer context.
  • ...但是外部创造了一个功能,中间。创建函数时,当前执行上下文将附加到函数。这就是它如何在外部环境中访问变量等。

  • outer calls middle, creating an inner execution context, and middle creates two other function (inner and caller), which each get that inner context attached to them. middle then returns caller, so caller exists after the call to middle completes. Since caller has a reference to the inner execution context, the context continues to exist (just like any other object), even though middle has returned. Since that context has a reference to inner, inner also continues to exist.
  • 外部调用中间,创建内部执行上下文,中间创建另外两个函数(内部和调用者),每个函数都附加到它们的内部上下文。中间然后返回调用者,因此调用中间完成后调用者存在。由于调用者具有对内部执行上下文的引用,因此上下文将继续存在(就像任何其他对象一样),即使中间已返回。既然那个上下文有内在的引用,内在也继续存在。

  • outer returns the return value of middle (which is caller), and so that means caller still exists when outer returns, which means the inner context it refers to still exists, which means inner still exists, and the outer context still exists because the inner context has a reference to it.
  • outer返回middle的返回值(也就是调用者),这意味着当外部返回时调用者仍然存在,这意味着它所引用的内部上下文仍然存在,这意味着内部仍然存在,并且外部上下文仍然存在,因为内部上下文有一个参考。

...which is how f1 and f2 have access to those arguments after outer returns: When you run them, they look up the values in the contexts attached to them.

...在外部返回之后,f1和f2如何访问这些参数:当您运行它们时,它们会查找附加到它们的上下文中的值。

#1


1  

It's a matter of scope. Code has access to the variables declared within the function, its containing function (if any), its containing function (if any), and so on, and then globals.

这是一个范围问题。代码可以访问函数内声明的变量,它包含的函数(如果有的话),它包含的函数(如果有的话),等等,然后是全局变量。

In your first example, readFileCallback is declared outside the form.on callback, and so it doesn't have access to things inside the form.on callback.

在第一个示例中,readFileCallback在form.on回调之外声明,因此它无法访问form.on回调中的内容。

In your second example, the function is inside the form.on callback, and so it does have access to the things inside it.

在第二个示例中,函数位于form.on回调中,因此它可以访问其中的内容。

Note that in the second example, in theory a new function is created each time the callback is called. That's fine, JavaScript engines are really fast at creating functions (and good ones will reuse the code even though a separate function object is created).

请注意,在第二个示例中,理论上每次调用回调时都会创建一个新函数。没关系,JavaScript引擎在创建函数方面非常快(即使创建了单独的函数对象,优秀的函数也会重用代码)。

Normally you want to create the function at the outermost location where it has access to everything it needs. So in your case, that would be inside form.on, but outside the readFile callback. Which is exactly where your second example has it. But you can use a named function like your first example if you like, just put it in form.on's callback:

通常,您希望在最外面的位置创建该功能,以便能够访问所需的一切。所以在你的情况下,这将在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;
      .... 
   }
});

Let's take an example where everything had a simple name, and follow through two calls:

让我们举一个例子,其中一切都有一个简单的名称,并通过两个调用:

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 contains middle which contains inner, and outer calls middle (and middle calls inner). A call:

outer包含中间,包含内部和外部调用中间(和中间调用内部)。一个电话:

outer("Test1");
  1. outer gets the arg "Test1"
  2. 外部获取arg“Test1”

  3. It calls middle with "TEST1"
  4. 它用“TEST1”调用中间

  5. It calls inner with "test1"
  6. 它用“test1”调用内部

  7. inner outputs:

    innerArg = test1
    middleArg = TEST1
    outerArg = Test1
    
  8. 内在输出: innerArg = test1 middleArg = TEST1 outerArg = Test1

So far, so simple, but it's more exciting than that: What if middle returns a function that calls inner, instead of calling it immediately, and outer returns returns middle's return value?

到目前为止,这么简单,但它比那更令人兴奋:如果中间返回一个调用内部的函数,而不是立即调用它,外部返回返回中间的返回值,该怎么办?

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());          // ***
}

Now, calling outer doesn't have any output at all:

现在,调用outer根本没有任何输出:

var f = outer("Test2");

But then calling the function middle returned (caller) does:

但后来调用函数middle返回(调用者):

f();

Output:

innerArg = test2
middleArg = TEST2
outerArg = Test2

The arguments still exist after outer and middle return! But it's even more interesting:

外部和中间回归后,这些论点仍然存在!但它更有趣:

var f1 = outer("Test3");
var f2 = outer("Test4");
f2();  // Note -- calling the second one first
f1();

Output:

innerArg = test4
middleArg = TEST4
outerArg = Test4
innerArg = test3
middleArg = TEST3
outerArg = Test3

So that means, two outerArgs still existed after both calls to outer had finished, along with two middleArgs. How?

这意味着,在两个外部调用完成后,两个outerArgs仍然存在,还有两个middleArgs。怎么样?

They exist on objects attached to the functions:

它们存在于附加到函数的对象上:

  • Calling outer creates an execution context (an object), which amongst other things (and leaving out a lot of details) holds the arguments and local variables for that call to outer. Let's call it the "outer context." It also has a reference to the execution context containing it (the global context, in our code). Normally that object gets cleaned up when a functon returns...
  • 调用外部会创建一个执行上下文(一个对象),除其他外(并省略很多细节)保存该外部调用的参数和局部变量。我们称之为“外部背景”。它还引用了包含它的执行上下文(我们的代码中的全局上下文)。通常,当一个功能返回时,该对象会被清理掉...

  • ...but outer creates a function, middle. When you create a function, the current execution context is attached to the function. That's how it has access to the variables and such in that outer context.
  • ...但是外部创造了一个功能,中间。创建函数时,当前执行上下文将附加到函数。这就是它如何在外部环境中访问变量等。

  • outer calls middle, creating an inner execution context, and middle creates two other function (inner and caller), which each get that inner context attached to them. middle then returns caller, so caller exists after the call to middle completes. Since caller has a reference to the inner execution context, the context continues to exist (just like any other object), even though middle has returned. Since that context has a reference to inner, inner also continues to exist.
  • 外部调用中间,创建内部执行上下文,中间创建另外两个函数(内部和调用者),每个函数都附加到它们的内部上下文。中间然后返回调用者,因此调用中间完成后调用者存在。由于调用者具有对内部执行上下文的引用,因此上下文将继续存在(就像任何其他对象一样),即使中间已返回。既然那个上下文有内在的引用,内在也继续存在。

  • outer returns the return value of middle (which is caller), and so that means caller still exists when outer returns, which means the inner context it refers to still exists, which means inner still exists, and the outer context still exists because the inner context has a reference to it.
  • outer返回middle的返回值(也就是调用者),这意味着当外部返回时调用者仍然存在,这意味着它所引用的内部上下文仍然存在,这意味着内部仍然存在,并且外部上下文仍然存在,因为内部上下文有一个参考。

...which is how f1 and f2 have access to those arguments after outer returns: When you run them, they look up the values in the contexts attached to them.

...在外部返回之后,f1和f2如何访问这些参数:当您运行它们时,它们会查找附加到它们的上下文中的值。