1

分配对象(例如数组)时,我不理解赋值运算符。我被告知,作为赋值运算符复制参考。但是,它似乎复制了数据。例如:

var globArray = [];

function test() {
  var names = ["craig", "silva"];
  globArray = names;
}//endFunction test

function test2() {
  console.log("el1: ", globArray[0], "el2: ", globArray[1]);
}//endFunction test2

当我调用 TEST 时,它会创建数组 NAMES 并将全局数组“globArray”分配给 NAMES。现在它超出了范围,所以“名称”消失了,对吧?后来我打电话给 test2,但它确实显示了元素!所以它必须复制整个对象,而不是仅仅处理引用。

有人可以解释一下吗?

4

5 回答 5

6

当您的“测试”函数返回时,您是正确的,“名称”已“消失”。但是,它的不是,因为它被分配给一个全局变量。“names”局部变量的是对数组对象的引用。该引用被复制到全局变量中,因此现在该全局变量还包含对数组对象的引用。

对象分配是全局性的。当一个对象被一个局部变量分配和引用时,除非存在对该对象的其他引用(直接或间接),否则当局部变量在其范围变为非活动时消失时,它将被垃圾收集。直接参考将是像您这样的案例。如果局部范围“泄漏”包含对局部变量的引用的函数,则可能发生间接引用。

于 2012-10-24T13:30:32.750 回答
3

这里有两件事在起作用:激活记录和堆上的对象。

您从全局变量的激活框架开始:

globArray : undefined

并且堆包含出现在您的代码中的文字

ptr0      : "craig"
ptr1      : "silva"

where ptr0,ptr1等只是引用内存中特定位置的地址或标签。

当您调用test()时,解释器会推送一个新的激活框架,其中包含局部变量的框。

globArray : undefined
---------------------
names     : undefined

然后解释器评估["craig", "silva"]哪个在堆上创建了一个对象。

ptr0      : "craig"
ptr1      : "silva"
ptr2      : [ &ptr0, &ptr1 ]

所以ptr2now 是内存中的一个位置,其中包含一个指向两个值的数组。

这个内存位置现在存储在names激活记录中的位置,所以你的调用堆栈看起来像

globArray : undefined
---------------------
names     : &ptr2

赋值names = ...不会改变堆,只会改变激活记录。

接下来globArray = names将一个激活记录条目的内容复制到另一个。

globArray : &ptr2
---------------------
names     : &ptr2

然后调用test结束,激活记录被丢弃,留下

globArray : &ptr2

全局globArray指向在调用test. 函数的结尾只是改变了活动的激活记录,而不是堆,所以堆看起来仍然像

ptr0      : "craig"
ptr1      : "silva"
ptr2      : [ &ptr0, &ptr1 ]

所以ptr2仍然是同一个数组。

所以“名字”不见了,对吧?

names(激活记录中的条目)消失了,但它指向的对象没有,因为它仍然被globArray活动激活记录中的条目指向。

后来我打电话给 test2,但它确实显示了元素!所以它必须复制整个对象

不,它只是复制了对该对象占用的堆中位置的引用。由于堆没有更改,因此没有创建新对象,并且堆是创建所有对象的地方。

堆栈和堆是什么以及在哪里?可能会感兴趣。

于 2012-10-24T13:38:29.837 回答
2

Javascript 对象是垃圾收集的。

变量引用的对象在退出names后会继续存在test(),因为它仍然被全局变量引用。

于 2012-10-24T13:31:12.080 回答
2

names 和 globalArray 都引用同一个对象。只要在范围内至少有一个对它的引用,这个对象就不会“消失”。你知道什么消失了吗?globalArray 引用的初始数组。

于 2012-10-24T13:32:08.317 回答
0

该对象与持有对它的引用的变量是分开的。即使变量消失后,对象可能仍然存在。这就是您的代码中发生的事情,即使names变量消失了,它引用的对象仍然独立于变量而存在name。只有当没有对对象的引用时,它才会从内存中删除。

您可以验证在分配对象时未复制数据。将对象分配给另一个变量后,您可以使用第一个变量更改对象,并且在使用另一个变量时它会更改:

function test() {
  var names = ["craig", "silva"];
  globArray = names;
  names[0] = 'peter';
}

现在,当您显示 的内容时globArray,您将看到petersilva,因为这两个变量都引用了同一个数组对象。

于 2012-10-24T13:39:25.757 回答