2010-11-18 110 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

相關問題