我正在生成一个函数并使用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
。当通过值传递的原始类型时,这不是通常的行为吗? ,为什么即使我使用传递引用(对象)也会发生同样的事情?
答案 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 | +−−−−−−−−−−−−−−−−+
请注意k
和j
具有相同的值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
的值未发生变化,因为k
和j
没有相互关联。
将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]()