理解javascript中的連續賦值

以前在扒源碼時常常看到相似的連續賦值操做:javascript

 var a = b = 1; 

在某度搜了衆多前輩的博客,總算對這騷操做有點眉目。java

Case analysis

首先,javascript中連續賦值最典型案例是:spa

var a = {n: 1}; 
var b = a;
a.x = a = {n: 2}; 
console.log(a.x); //undefined 
console.log(b.x); //{n: 2} 

 

Analysis in short

var a = {n: 1}; //建立對象{n: 1},a指向對象{n: 1}
var b = a; //將 a中的地址傳給b,即 b也指向對象{n: 1}
a.x = a = {n: 2}; 
/*
1)建立對象{n: 1}中的"x"屬性
2)將a指向新對象{n: 2}
3) 將對象{n: 1}中的"x"指向新對象{n: 2}
*/
console.log(a.x); //undefined 
console.log(b.x); //{n: 2} 

 若是看懂了,下面能夠直接忽略2333指針

 

 Analysis in long

我概括了一下,要看懂這個問題要理解三個點:code

  • 此處的a,b是引用類型對象

  • 在javascript中字段訪問操做符"."的優先級高於賦值操做符"="blog

  • 出現多個賦值操做符"="時,運算順序爲從右向左ip

 

1. 此處的a,b是引用類型get

引用類型是區別於基本類型的。javasript中的基本類型總共有5種,Undefined、Null、String、Number、Boolean。引用類型有Object,Array,Function,,,blabla~,簡單說就是除了5種基本類型,能夠說其它都爲引用類型。源碼

案例中的{n: 1}和{n: 2}都爲Object類,即爲引用類型。在javascript中當複製保存某個對象時,操做的是對象的引用,但在爲對象添加屬性時,操做的是實際的對象。即在第一行和第二行命令中a,b其實存儲的是對象{n: 1}的引用(地址)。

這有點像C中的指針。以下圖,案例第一行命令能夠解析爲,在堆(heap)中建立了一個對象{n: 1},另外在棧(stack)中建立了變量a,變量a的值爲對象{n: 1}的地址,即圖中的h[0]。第二行命令意思是再在棧中建立另外一個變量b,變量b的值與變量a的值相等,即爲對象{n: 1}的地址。

打個比方,你有一張去餐館的地圖,你把地圖複製一份給你的基友,地圖是多了一張,但餐館的實際位置是沒有改變的。

2. 運算順序問題

這一節對應的是第二和第三個點。根據javascript中的運算符優先級 Operator precedence,可知:

  • 在javascript中字段訪問操做符"."的優先級高於賦值操做符"="
  • 出現多個賦值操做符"="時,運算順序爲從右向左

所以在運行第三行命令時,分3步執行:

(1)先執行"a.x",此時a儲存的仍然是h[0]地址,即指向對象{n: 1}。"a.x"至關於"h[0].x",即在對象{n: 1}中添加了屬性"x",變爲{n: 1; x: undefined},可是"x"還沒賦值;注意,此時對象{n: 1; x: undefined}中的"x"屬性是等待賦值的,操做掛起

 (2)再執行"a = {n: 2}",因爲{n: 2}是個新對象,則程序在堆中再建立一個對象{n: 2},而且將變量a指向該對象,如圖,此時a儲存的即爲h[1]的地址

(3)最後一步"a.x = a",(1)中被掛起的操做繼續執行,對象{n: 1; x: undefined}中的"x"指向對象{n: 2}。運算完成。

3. 結果解釋

在運行完上述命令後,變量a指向了新對象{n : 2};變量b 的地址沒有發生改變,於是仍指向修改後的對象{n: 1;x: {n : 2}}。

var a = {n: 1}; 
var b = a; 
a.x = a = {n: 2}; 
console.log(a.x); //undefined 
console.log(b.x); //{n: 2} 
相關文章
相關標籤/搜索