需要帮助理解JS代码

时间:2012-11-19 17:19:35

标签: javascript closures

您好我是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)在新代码的函数末尾使用?

3 个答案:

答案 0 :(得分:2)

在JavaScript中,我们没有块范围,只有函数范围。

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

i

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

在IIFE内部创建的函数将访问IIFE的执行上下文// 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 }); } 。当您将外部i传递给IIFE时,此i对于每次迭代都是唯一的,这将成为IIFE的形式参数i

简而言之,每次迭代都会通过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中的形式参数i。该功能已创建。

答案 1 :(得分:1)

在第一个块中,createAdders()返回一个函数数组,并且每个函数(在for函数体的内部createAdders()循环中创建)总和参数{{1在循环中创建变量n的(7值),在循环结束时,其值为4(这解释了11)。

当您进行调用i时,返回存储在位置1的数组adders[1](7)中的函数,然后使用参数fns调用该函数,然后函数前进到求和此参数包含n = 7函数的i变量(当前调用createAdders的值为4

答案 2 :(得分:0)

在javascript中,即使外部函数执行完毕,内部函数也始终可以访问它们的外部函数变量。此行为称为Closure。

在第一个片段中,你迭代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