年前寫了一篇部落格,立了一個flag說是以後一個星期寫一篇部落格,但被年前的997和過年給耽誤了,算了一下一共欠了四篇部落格,後續會補上
從18年到這篇部落格之前都是在簡書上寫,當然寫的都是一些淺顯一點的東西,也獲得了幾十個粉絲和不少贊(慚愧),寫的都是一些工具的使用,經過了一年的磨練以後,後面也會寫一點稍微深入一點的東西,或者是更原理一些的東西,望共勉
昨天水群的時候看到有人發了一道很有意思的面試題,看起來簡單,但是答錯的人倒是佔了十之八九,還有一些人可能是之前看過類似的題,但是解釋的也是差強人意,所以就自己研究了一番
題目是這樣的
var obj = {n:1}
var newObj = obj
obj.m = obj = {n:2}
console.log(obj)
console.log(newObj)
複製程式碼
題目就這麼長,答案是 obj = {n: 2}, newObj = {n: 1, m: {n:2}}
小夥伴們答對了嗎?
其實最主要的就是那段連等賦值的程式碼,在分析這段程式碼之前我們先看一個簡單的連等程式碼
let obj;
let obj1 = obj = {name: 'zhangsan'}
複製程式碼
思考一下這個賦值操作時怎麼進行的
是這樣的???
拆分1
let obj1 = {name: 'zhangsan']
obj = {name: 'zhangsan'}
複製程式碼
還是這樣的?
拆分2
obj = {name: 'zhangsan'}
let obj1 = obj
複製程式碼
上面兩段程式碼的拆分,第一個是兩個物件分別指向不同的記憶體地址,第二個是指向同一個記憶體地址
那我們來驗證一下,看修改其中一個的值另一個會不會改變
let obj;
let obj1 = obj = {name: 'zhangsan'}
//測試改值
obj.name = 'lisi'
console.log(obj1.name) // 'lisi'
複製程式碼
看來好像是指向同一塊地址的,難道是拆分2這樣的???
帶著這個疑問繼續看我們的面試題,拆分一下
var obj = {n:1}
var newObj = obj
obj = {n:2}
obj.m = obj
console.log(obj) //{n:2,m:{n:2,m: {...}}}
console.log(newObj) //{n: 1}
複製程式碼
拆分之後輸出的結果和不拆分的時候結果是不一樣的
以上的測試得出這篇文章的第一個結論:
連等程式碼是不可拆分的
接下來繼續分析面試題,看看這段程式碼到底做了什麼
obj.m = obj = {n:2}
複製程式碼
我們都知道賦值是從右向左賦值的
所以上面的程式碼 相當於下面的三步
賦值操作之前編譯器就已經讀取到了變數和它的屬性m,然後編譯器會在作用域中查詢物件是否有m屬性,沒有的話就會生成m屬性
賦值之前讀取當obj還有m屬性,所以把他新增到記憶體裡面,因為需要等待右邊賦值完成所以暫時指定為null
從右側開始賦值,即執行obj = {n: 2}, '=' 賦值就相當於new Object()的語法糖所以新建立了一塊記憶體空間
賦值到左側的時候m的屬性值指向了obj的新記憶體地址
這個時候我們在測試一下
var obj = {n:1}
var newObj = obj
obj.m = obj = {n:2}
//改變n的值
obj.n = 100
console.log(obj) //{n: 100}
console.log(newObj) //{n: 1,m: {n: 100}}
複製程式碼
看來上述的三步分解是正確的
但是實際開發中還是要謹慎使用連等,避免造成不必要的麻煩