2010-11-18 90 views
2

考虑JavaScript代码的这一点点:为什么更改一个数组会改变另一个数组?

var a = [1, 2, 3], 
    b = a; 

b[1] = 3; 

a; // a === [1, 3, 3] wtf!? 

为什么 “” 改变,当我更新 “B [1]”?我已经在Firefox和Chrome中测试过它。例如,这不会发生在简单的数字上。这是预期的行为?

var a = 1, 
    b = a; 

b = 3; 

a; // a === 1 phew! 

回答

8

因为“a”和“b”参照相同的阵列。他们中没有两个;将“a”的值分配给“b”将参考分配给阵列而不是 a 拷贝阵列。

当您分配号码时,您正在处理原始类型。即使在Number实例中,也没有办法更新该值。

你可以看到相同的“他们指向同一个对象”与Date实例的行为:

var d1 = new Date(), d2 = d1; 
d1.setMonth(11); d1.setDate(25); 
alert(d2.toString()); // alerts Christmas day 
+0

感谢您的好解释!我之前没有遇到过... – 2010-11-18 23:36:50

0

因为数组是引用它们存储的实际位置。

+0

变量是指存储对象的地方,更多的问题在这里 – Gareth 2010-11-18 23:16:59

+0

@Gareth这就是我所说的......数组是一个变量,当你使用数组的时候你认为数组的方式不是用它们是如何存储的,但是它们是如何使用的(作为变量)。 – 2010-11-18 23:21:44

6

这是相同的阵列(因为它是一个对象,它是相同的),你需要创建副本,分别操纵他们使用.slice()(这将创建与复制的第一级元素的数组),就像这样:

var a = [1, 2, 3], 
    b = a.slice(); 

b[1] = 3; 

a; // a === [1, 2, 3] 
+1

你应该解释为什么你使用切片...并且还提到副本只有一个深度 – 2010-11-18 23:16:37

+0

@Juan - 我提供了一个直接链接到一些最好的文档可用于完整的解释,但在这里增加了一点。 – 2010-11-18 23:17:25

+0

感谢.slice()解决方案!这将被用于很多:) – 2010-11-18 23:33:47

2

除了其他的答案,如果你想要的副本数组,一种方法是使用分片方法:

var b = a.slice(0) 
0

声明x = y是这里唯一特殊的一个,它的意思是“在对象y点变量x

几乎所有其他的操作是由x

b = a; 
b[1] = 3; 

改变所指的对象的操作所以,你的第一条语句点在数组变量b也被称为a

你的第二个语句更改b指向的数组(以及a

0

指定数组不会创建新数组,它只是对同一个数组的引用。数字和布尔值在分配给新变量时被复制。

1

所有Javascript对象都通过引用传递 - 您需要复制整个对象,而不是分配它。

对于数组,这将是简单的 - 只是这样做:

var a = [1, 2, 3]; 
var b = a.slice(0); 

其中slice(0)返回从偏移0到数组末尾的数组。

This link有更多信息。

1

Value typesReference types之间的差。

Basicly Value类型直接存储在计算机“堆栈”上,这意味着您实际上具有“值”而不是所谓的指针/参考。

另一方面,引用类型不包含对象/变量的实际值,而是指向(引用)到您可以找到值的位置。

因此,当您说“我的参考类型B指向参考类型A指向的内容”时,您实际上有两个变量指向相同的方向,当您与其中任何一个进行交互并更改某些内容时,两者都会指向自改变的地方,因为从开始指向相同的地方。

在另一种情况下,您会说“嘿,将变量A中的值复制到变量B中”,因此您具有单独位置上的值,这意味着对其中任何一个的任何更改都不会影响其他值。

+0

只是为了纠正你的最后一点。当值为数字时,赋值* *不*不同。第二个例子不同的原因是因为*更改*('b = 3')是另一个赋值,它早先对原始对象 – Gareth 2010-11-18 23:24:07

+0

@Gareth做出了可变更改,这不是我说的吗?该作业复制了该值,因此当您更改该值时,它不会影响“a”。 – 2010-11-18 23:25:32

+0

对不起,我在第一次阅读时得到的印象是,你将基元和其他对象区分为右值。我的错 – Gareth 2010-11-18 23:29:04

相关问题