以前在扒源碼時常常看到相似的連續賦值操做:javascript
var a = b = 1;
在某度搜了衆多前輩的博客,總算對這騷操做有點眉目。java
首先,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}
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指針
我概括了一下,要看懂這個問題要理解三個點: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,可知:
所以在運行第三行命令時,分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}