在分配对象(比如数组)时,我不理解赋值运算符。我被告知,作为赋值运算符复制引用。然而,它似乎复制数据。例如:
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,但它会显示元素!因此,它必须使整个对象复制,而不是仅仅应对参考。
有人可以解释一下吗?
答案 0 :(得分:6)
当你的“测试”功能返回时,你说“名字”已“消失”是正确的。但是,它的值不是,因为它已被分配给全局变量。 “names”局部变量的值是数组对象的引用。该引用被复制到全局变量中,所以现在该全局变量还包含对数组对象的引用。
对象分配是一个全局性的事情。当一个对象被局部变量分配和引用时,当局部变量在其范围变为非活动状态时消失时,它将被垃圾收集,除非存在对象的某些其他引用(直接或间接)。直接引用就像你的情况一样。如果本地范围“泄漏”包含对局部变量的引用的函数,则可能发生间接引用。
答案 1 :(得分:3)
这里有两件事情:激活记录和堆上的对象。
您从全局变量的激活框架开始:
globArray : undefined
并且堆包含出现在代码中的文字
ptr0 : "craig"
ptr1 : "silva"
其中ptr0
,ptr1
等只是引用内存中特定位置的地址或标签。
当您致电test()
时,解释程序会推送一个新的激活框,其中包含局部变量的框。
globArray : undefined
---------------------
names : undefined
然后解释器评估在堆上创建对象的["craig", "silva"]
。
ptr0 : "craig"
ptr1 : "silva"
ptr2 : [ &ptr0, &ptr1 ]
所以ptr2
现在是内存中一个包含指向两个值的数组的位置。
此内存位置现在存储在激活记录的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,但它会显示元素!所以它必须让COPIED整个对象
不,它只是复制了对该对象占用的堆中的位置的引用。由于未更改堆,因此没有创建新对象,并且堆是创建所有对象的位置。
What and where are the stack and heap?可能会引起人们的兴趣。
答案 2 :(得分:2)
Javascript对象被垃圾收集。
names
变量引用的对象将在test()
退出后继续存在,因为它仍然被全局变量引用。
答案 3 :(得分:2)
名称和globalArray都引用同一个对象。只要在范围内至少有一个对象引用,该对象就不会“消失”。你知道什么消失了吗?初始数组globalArray引用。
答案 4 :(得分:0)
该对象与保存对它的引用的变量分开。即使在变量消失之后,对象仍可能存在。这就是代码中发生的事情,即使names
变量消失,它引用的对象仍然独立于变量name
而存在。只有当对象没有引用时,它才会从内存中删除。
您可以在分配对象时验证是否未复制数据。将对象分配给另一个变量后,可以使用第一个变量更改对象,并在使用另一个变量时更改对象:
function test() {
var names = ["craig", "silva"];
globArray = names;
names[0] = 'peter';
}
现在,当您显示globArray
的内容时,您会看到peter
和silva
,因为这两个变量都引用了同一个数组对象。