将对象传递给IIFE

时间:2016-06-06 13:45:03

标签: javascript closures

我正在生成一个函数并使用IIFE将其推送到数组,如下所示:

var arr = [];
  var k;
  for(var i=0;i<3;i++) {
    k = {"val" : i};
    arr.push(
      (function(j) {
        return function() {
          console.log(j)
        };
      }(k))
    )
  }
console.log(arr[0](), arr[1](), arr[2]());

输出:

Object {val: 0}
Object {val: 1}
Object {val: 2}

但是我传递k,这是使用i生成的对象。由于对象是通过引用传递的,因此我希望它能够记录值为2,2,2的对象,但我获得了0,1,2。当通过值传递的原始类型时,这不是通常的行为吗? ,为什么即使我使用传递引用(对象)也会发生同样的事情?

3 个答案:

答案 0 :(得分:4)

你得到0,1,2而不是3,3,3,因为k被传递到函数中。 k是对象引用。 JavaScript没有任何形式的pass-by-reference,因此函数接收的不是对k 变量的引用,它是k中对象引用的副本。 1}}当你调用函数时。在下一个传递中,您创建一个新对象并将其放在k变量中,但这对最内层函数关闭的j变量的值完全没有影响。

将对象引用想象成一个大数组(内存)的索引,它告诉JavaScript引擎对象所在的位置。 k包含该引用(数字),而不是实际对象。将引用复制到第二个变量(或将其传递给函数)时,对象只有两个引用副本,但只有一个对象。

让我们简化,并在其上抛出一些ASCII艺术:: - )

var k = {val: 0};

在这些代码行之后,这是我们在内存中的内容(省略了一些不必要的细节):

                     +−−−−−−−−−−−−−−−−+
k:REF#123−−−−−−−−−−−>| Object@REF#123 |
                     +−−−−−−−−−−−−−−−−+
                     | val: 0         |
                     +−−−−−−−−−−−−−−−−+

k包含引用(我任意称之为REF#123,但我们实际上从未看到原始值);对象在别处。

现在,如果我们这样做:

var j = k;

......我们有这个:

k:REF#123−−−−−−+
               |     +−−−−−−−−−−−−−−−−+
               +−−−−>| Object@REF#123 |
               |     +−−−−−−−−−−−−−−−−+
j:REF#123−−−−−−+     | val: 0         |
                     +−−−−−−−−−−−−−−−−+

请注意kj具有相同的值REF#123。因此,无论您查看哪个变量,JavaScript引擎都将转到内存中的该对象。

现在假设我们这样做:

k = {val: 1};

现在我们有了一个新对象,它有一个不同的引用:

                     +−−−−−−−−−−−−−−−−+
k:REF#462−−−−−−−−−−−>| Object@REF#462 |
                     +−−−−−−−−−−−−−−−−+
                     | val: 1         |
                     +−−−−−−−−−−−−−−−−+

                     +−−−−−−−−−−−−−−−−+
j:REF#123−−−−−−−−−−−>| Object@REF#123 |
                     +−−−−−−−−−−−−−−−−+
                     | val: 0         |
                     +−−−−−−−−−−−−−−−−++

{val: 1}创建了一个新对象。将该对象的引用分配给k会给它一个新值(新对象的引用)。 j的值未发生变化,因为kj没有相互关联。

k传递给函数并将值作为j接收就像上面的j = k一样:k已通过进入函数,并输入参数j。回到原始代码:

var arr = [];
  var k;
  for(var i=0;i<3;i++) {
    k = {"val" : i};
    arr.push(
      (function(j) {
        return function() {
          console.log(j)
        };
      }(k))
    )
  }
console.log(arr[0](), arr[1](), arr[2]());

...每次调用中间的IIFE都会创建一个执行上下文,并附加一个环境记录。从概念上讲,环境记录是包含变量和参数值的对象,对于函数调用是这样的(您无法在代码中访问此对象,它是规范中的概念,不一定是JavaScript引擎中的文字内容)。该环境记录包含j参数。 IIFE创建了一个新函数,它记住了对它所创建的环境的引用(使用一个名为[[Environment]]的内部插槽),并返回该函数;函数被推入数组。

所以这是第一个循环之后的内存(再次遗漏了一些不必要的细节):

                                                                +−−−−−−−−−−−−−−+
k−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−>| Object@REF#2 |
                                                             |  +−−−−−−−−−−−−−−+
       +−−−−−−−−−−+                                          |  | val: 0       |
arr−−−>|  Array   |                                          |  +−−−−−−−−−−−−−−+
       +−−−−−−−−−−+     +−−−−−−−−−−−−−−−−−+                  |
       | 0: REF#1 |−−−−>| Function@REF#1  |                  |
       | 1: REF#3 |−−+  +−−−−−−−−−−−−−−−−−+  +−−−−−−−−−−−−−+ |
       +−−−−−−−−−−+  |  | [[Environment]] |−>| Environment | |
                     |  +−−−−−−−−−−−−−−−−−+  +−−−−−−−−−−−−−+ |
                     |                       | j: REF#2    |−+
                     |                       +−−−−−−−−−−−−−+
                     |  +−−−−−−−−−−−−−−−−−+
                     +−>| Function@REF#3  |
                        +−−−−−−−−−−−−−−−−−+  +−−−−−−−−−−−−−+
                        | [[Environment]] |−>| Environment |
                        +−−−−−−−−−−−−−−−−−+  +−−−−−−−−−−−−−+
                                             | j: REF#4    |
                                             +−−−−−−−−−−−−−+

在第二个循环之后,你有这个:

                                                                                    +−−−−−−−−−−−−−−+
k−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−>| Object@REF#4 |
                                                                                 |  +−−−−−−−−−−−−−−+
                                                                                 |  | val: 1       |
                                                                +−−−−−−−−−−−−−−+ |  +−−−−−−−−−−−−−−+
                                                             +−>| Object@REF#2 | |
                                                             |  +−−−−−−−−−−−−−−+ |
                                                             |  | val: 0       | |
                                                             |  +−−−−−−−−−−−−−−+ |
                                                             |                   |
                                                             |                   |
       +−−−−−−−−−−+                                          |                   |
arr−−−>|  Array   |                                          |                   |
       +−−−−−−−−−−+    +−−−−−−−−−−−−−−−−−+                   |                   |
       | 0: REF#1 |−−−>| Function@REF#1  |                   |                   |
       | 1: REF#3 |−+  +−−−−−−−−−−−−−−−−−+   +−−−−−−−−−−−−−+ |                   |
       +−−−−−−−−−−+ |  | [[Environment]] |−−>| Environment | |                   |
                    |  +−−−−−−−−−−−−−−−−−+   +−−−−−−−−−−−−−+ |                   |
                    |                        | j: REF#2    |−+                   |
                    |                        +−−−−−−−−−−−−−+                     |
                    |  +−−−−−−−−−−−−−−−−−+                                       |
                    +−>| Function@REF#3  |                                       |
                       +−−−−−−−−−−−−−−−−−+   +−−−−−−−−−−−−−+                     |
                       | [[Environment]] |−−>| Environment |                     |
                       +−−−−−−−−−−−−−−−−−+   +−−−−−−−−−−−−−+                     |
                                             | j: REF#4    |−−−−−−−−−−−−−−−−−−−−−+
                                             +−−−−−−−−−−−−−+

然后在第三个之后:

                                                                                                           +−−−−−−−−−−−−−−+
k−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−>| Object@REF#6 |
                                                                                                        |  +−−−−−−−−−−−−−−+
                                                                                                        |  | val: 2       |
                                                                                       +−−−−−−−−−−−−−−+ |  +−−−−−−−−−−−−−−+
                                                                                    +−>| Object@REF#4 | |
                                                                                    |  +−−−−−−−−−−−−−−+ |
                                                                                    |  | val: 1       | |
                                                                   +−−−−−−−−−−−−−−+ |  +−−−−−−−−−−−−−−+ |
                                                                +−>| Object@REF#2 | |                   |
                                                                |  +−−−−−−−−−−−−−−+ |                   |
                                                                |  | val: 0       | |                   |
                                                                |  +−−−−−−−−−−−−−−+ |                   |
                                                                |                   |                   |
                                                                |                   |                   |
       +−−−−−−−−−−+                                             |                   |                   |
arr−−−>|  Array   |                                             |                   |                   |
       +−−−−−−−−−−+       +−−−−−−−−−−−−−−−−−+                   |                   |                   |
       | 0: REF#1 |−−−−−−>| Function@REF#1  |                   |                   |                   |
       | 1: REF#3 |−−−−+  +−−−−−−−−−−−−−−−−−+   +−−−−−−−−−−−−−+ |                   |                   |
       | 2: REF#5 |−−+ |  | [[Environment]] |−−>| Environment | |                   |                   |
       +−−−−−−−−−−+  | |  +−−−−−−−−−−−−−−−−−+   +−−−−−−−−−−−−−+ |                   |                   |
                     | |                        | j: REF#2    |−+                   |                   |
                     | |                        +−−−−−−−−−−−−−+                     |                   |
                     | |  +−−−−−−−−−−−−−−−−−+                                       |                   |
                     | +−>| Function@REF#3  |                                       |                   |
                     |    +−−−−−−−−−−−−−−−−−+   +−−−−−−−−−−−−−+                     |                   |
                     |    | [[Environment]] |−−>| Environment |                     |                   |
                     |    +−−−−−−−−−−−−−−−−−+   +−−−−−−−−−−−−−+                     |                   |
                     |                          | j: REF#4    |−−−−−−−−−−−−−−−−−−−−−+                   |
                     |                          +−−−−−−−−−−−−−+                                         |
                     |    +−−−−−−−−−−−−−−−−−+                                                           |
                     +−−−>| Function@REF#5  |                                                           |
                          +−−−−−−−−−−−−−−−−−+   +−−−−−−−−−−−−−+                                         |
                          | [[Environment]] |−−>| Environment |                                         |
                          +−−−−−−−−−−−−−−−−−+   +−−−−−−−−−−−−−+                                         |
                                                | j: REF#6    |−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
                                                +−−−−−−−−−−−−−+

答案 1 :(得分:1)

使用k = {"val" : i};您正在创建一个新对象并将其分配给k。请改为var k = {}k.val = i

答案 2 :(得分:-2)

你找到了一种使用闭包的好方法。使用诸如数字之类的原语,javascript将值创建/复制到新变量中,这就是为什么你看到0,1,2。

选中此示例:https://jsfiddle.net/hrjLvgr9/

请注意arr[0]arr[1]arr[2]如何按预期返回3。

var arr = [];
var k;

for(var i = 0; i < 3; i++) {
    arr.push(function() {
        console.log(i)
    })
}

for(var i = 0; i < 3; i++) {
    (function(j) {
        arr.push(function() {
            console.log(j)
        })
    })(i)
}

arr[0]()
arr[1]()
arr[2]()
arr[3]()
arr[4]()
arr[5]()