連等的思考

yourdearBrother發表於2019-02-21

年前寫了一篇部落格,立了一個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}}
複製程式碼

看來上述的三步分解是正確的

但是實際開發中還是要謹慎使用連等,避免造成不必要的麻煩

相關文章