1

嗨,我是 javascript 新手,无法理解以下代码:

var createAdders = function () {

    var fns = [];

    for (var i = 1; i < 4; i++) {

        fns[i] = (function (n) {
            return i + n;
        });
    }
    return fns;
}
var adders = createAdders();
adders[1](7); //11 ??
adders[2](7); //11 ??
adders[3](7); //11 ??

据我了解, 7 作为参数传递,但createAdders()没有将 7 分配给任何变量,这是否意味着 7 被传递给下一个函数,createAdders()即匿名函数并分配给变量n

我的逻辑正确吗?

上面的代码似乎确实有效,但每次调用的结果都是 11。我在一个非常可靠的博客中找到了这段代码作为闭包有用的示例。然后以以下方式更改上面的代码以引用闭包的优点。

var createAdders = function () {
    var fns = [];
    for (var i = 1; i < 4; i++) {
        (function (i) {
            fns[i] = (function (n) {
                return i + n;
            });
        })(i)     //// why is (i) used here? what purpose does it serve??////
    }
    return fns;
}

var adders = createAdders();
adders[1](7); //8 
adders[2](7); //9 
adders[3](7); //10

这里是否也应用了相同的逻辑?

我需要了解如何为 n 分配值 7

为什么在新代码的函数末尾使用 (i)?

4

3 回答 3

2

在 JavaScript 中,我们没有块作用域,只有函数作用域。

在第一个示例中,唯一i声明的属于createAdders范围,这意味着在循环中创建的所有函数for都将在范围链中查找相同的内容i并返回相同的值。用代码解释:

//   here's the only `i` declaration
for (var i = 1; i < 4; i++) {

    fns[i] = (function (n) {
        return i + n; //this line will retrieve the `i` variable declared above,
                      //that being always 4 after the loop ends
    });
}

在第二个示例中,您将在循环内创建一个带有IIFE的新范围- 它为每次迭代创建一个新的执行上下文。

在 IIFE 内部创建的函数将访问 IIFE 的执行上下文的i. 这i对于每次迭代都是唯一的,因为您将外部传递i给 IIFE,这将成为 IIFE 的形式参数i

简而言之,每次迭代都会i通过 IIFE 包装器创建一个新的执行上下文。

按顺序阅读评论:

//  1. Outer `i` declared here
for (var i = 1; i < 4; i++) {
    (function (i) {// 3. Outer `i` becomes the formal parameter `i` of the IIFE, 
                   // it is a "different" `i` in a new execution context (scope)
        fns[i] = (function (n) {
            return i + n; // 4. seeks the `i` value of the IIFE
        });
    })(i) // 2. Outer `i` passed to IIFE
}

当您调用在 IIFE 内创建的函数时,作用域链将检索作用域链中“最接近的” ,即创建函数的 IIFEi的形式参数。i

于 2012-11-19T17:34:57.357 回答
1

在第一个块中,createAdders()返回一个函数数组,每个函数(在函数体的内部for循环中创建createAdders())将参数n(7 值)与i在循环中创建的变量相加,至此,在循环结束时,值为 4(这解释了 11)。

当您进行调用时,将返回adders[1](7)存储在数组fns中位置 1 的函数,然后使用参数调用该函数n = 7,然后该函数继续将此参数与函数的i变量相加createAdders(此时该值是4invoke adders[1](7)

于 2012-11-19T17:25:53.010 回答
0

在 javascript 中,即使在外部函数完成执行后,内部函数也始终可以访问其外部函数变量。这种行为称为闭包。

在第一个片段中,您将迭代 3 次并将函数推入数组。当循环完成执行时,您的变量 i 设置为 4。您推入数组的函数可以访问此变量。所以无论你在数组的哪个索引处执行函数,你总是得到 11(4 + 7)。

在第二个片段中,您正在使用一个自执行匿名函数来保存 i 的值。这个匿名函数会在每次交互时立即执行。因为这个匿名函数内部定义的闭包函数每次都会引用 i 的新值。

所以你在数组中有一个三个函数,每个函数都有单独的值 i (1,2,3) 如下编写第二个片段可以更清楚

var createAdders = function(){
var fns = [ ];
for (var i=1; i<4; i++) { 
    (function(a) {
        fns[a] = (function(n) {
            return a+n;
        });
    })(i)    
}
return fns;}

在javascript中,您可以将函数作为返回值。其次,数组可以在自己内部存储函数。

您在代码中所做的是在数组中推送一个函数,该函数接受单个参数,然后调用它。

adders[1](7);

可以分解如下

var fn = adders[1];
fn(7); //thats how n is set to 7
于 2012-11-19T18:26:03.840 回答