我发现了一个奇怪的JS行为:
var myArray = [ [1] , [2] , [3] ];
var myArrayCopy = [];
myArrayCopy.push( myArray[1] );
alert( myArrayCopy ); // 2, as expected.
myArrayCopy[0][0] = 'foo';
alert( myArrayCopy ); // 'foo', as expected.
alert( myArray ); // 1, foo, 3 = WTF ? :)
请参阅Demo。
请注意,如果我们直接推送值而不是数组,这不起作用。
对我而言,它看起来像是将数组推入数组,转换为某种方式,好像我们只推送对那些数组的引用而不是副本(这不是人们所期望的行为,如果我错了,请更正)。
有人可以解释原因吗?
答案 0 :(得分:2)
混叠
您正在myArrayCopy
添加myArray
中包含的现有对象(数组)的引用。因此,当您修改该数组时,您正在修改从上述两个数组引用的实际对象。
请注意,当您在JavaScript中传递对象时,它们不会被复制,而是传递对实例的引用并在接收器的范围内修改它将导致调用者范围内的已修改对象同样。 这个规则有一些值得注意的例外(例如,它们不是对象的原始类型,或者它们实际上是在写入时复制的字符串,等等),但让我们专注于你的问题。
考虑到数组是一个对象,它在下面的例子中发生的情况相同,但从我的观点来看它更清楚:
var o = { "foo": " bar" };
myArray[0] = o;
myArrayCopy[0] = myArray[0];
o.foo = "nolongerbar";
它返回myArrayCopy[0].foo
的内容是什么?什么是myArray[0].foo
?
在大多数OO语言中称为别名,无论如何,当你处理对象时,它是一个常见的错误'引用。
修改强>
哦,它不是任何情况下的同步技巧,它通常是烦人的bug背后的原因。 : - )
答案 1 :(得分:2)
[2]
的值是一个数组(myArrayCopy
)。当您将其推送到myArrayCopy.push( myArray[1] );
中的[2]
时,您会推送数组,而不是它的内容(2
而不是myArrayCopy[0][0] = 'foo';
)。
当你稍后改变这个数组(fc = fc.set_index(fc.index.dayofyear)
)时,它显然会在使用这个数组的任何地方产生影响。
答案 2 :(得分:0)
是的,这是有意义的动作,因为myArray 1和myArrayCopy [0]具有相同的内存地址。您可以查看以下调试捕获
在通过第9行后,那些已被同时更改为myArray和myArraycopy的值为'foo'
答案 3 :(得分:-2)
这是完全正确的。
由于数组充当对象,因此它存储内存地址 而不是存储值本身。
var myArray = [ [1] , [2] , [3] ];
myArray
将存储创建的数组的地址(比如addr-1
)。
由于数组的元素本身就是一个数组,它现在有三个地址对应于数组[1]
,[2]
,[3]
说addr-2
,{{1 },addr-3
。
所以最后我们有:
addr-4
addr-1 = [addr-2,addr-3,addr-4]
这将存储一个新地址var myArrayCopy = [];
:
addr-5 = []
因为您将myArrayCopy.push(myArray[1]);
的第一个元素推送到myArray
。它将存储地址myArrayCopy
。像这样addr-3
:
addr-5 = [addr-3]
当然,这可以正常工作`alert( myArrayCopy ); // 2, as expected
:
addr-3 = [2]
这里你要修改myArrayCopy[0][0] = 'foo';
的第0个元素的第0个元素的值,即你将myArrayCopy
的第一个元素更改为addr-3
foo
所以它也有效:
alert( myArrayCopy ); // 'foo', as expected
alert( myArray ); // 1, foo, 3
现在有myArray
,其中addr-1 = [addr-2, addr-3, addr-4]
,addr-2 = [1]
和addr-3 = ["foo"]
。