年前寫了一篇博客,立了一個(gè)flag說是以后一個(gè)星期寫一篇博客,但被年前的997和過年給耽誤了,算了一下一共欠了四篇博客,后續(xù)會補(bǔ)上
從18年到這篇博客之前都是在簡書上寫,當(dāng)然寫的都是一些淺顯一點(diǎn)的東西,也獲得了幾十個(gè)粉絲和不少贊(慚愧),寫的都是一些工具的使用,經(jīng)過了一年的磨練以后,后面也會寫一點(diǎn)稍微深入一點(diǎn)的東西,或者是更原理一些的東西,望共勉
昨天水群的時(shí)候看到有人發(fā)了一道很有意思的面試題,看起來簡單,但是答錯(cuò)的人倒是占了十之八九,還有一些人可能是之前看過類似的題,但是解釋的也是差強(qiáng)人意,所以就自己研究了一番
題目是這樣的
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}}
小伙伴們答對了嗎?
其實(shí)最主要的就是那段連等賦值的代碼,在分析這段代碼之前我們先看一個(gè)簡單的連等代碼
let obj;
let obj1 = obj = {name: 'zhangsan'}
思考一下這個(gè)賦值操作時(shí)怎么進(jìn)行的
是這樣的???
拆分1
let obj1 = {name: 'zhangsan']
obj = {name: 'zhangsan'}
還是這樣的?
拆分2
obj = {name: 'zhangsan'}
let obj1 = obj
上面兩段代碼的拆分,第一個(gè)是兩個(gè)對象分別指向不同的內(nèi)存地址,第二個(gè)是指向同一個(gè)內(nèi)存地址
那我們來驗(yàn)證一下,看修改其中一個(gè)的值另一個(gè)會不會改變
let obj;
let obj1 = obj = {name: 'zhangsan'}
//測試改值
obj.name = 'lisi'
console.log(obj1.name) // 'lisi'
看來好像是指向同一塊地址的,難道是拆分2這樣的???
帶著這個(gè)疑問繼續(xù)看我們的面試題,拆分一下
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}
拆分之后輸出的結(jié)果和不拆分的時(shí)候結(jié)果是不一樣的
以上的測試得出這篇文章的第一個(gè)結(jié)論:
<font color='#ff0000'>連等代碼是不可拆分的</font>
接下來繼續(xù)分析面試題,看看這段代碼到底做了什么
obj.m = obj = {n:2}
我們都知道賦值是從右向左賦值的
所以上面的代碼 相當(dāng)于下面的三步
<font color='#ff0000'>賦值操作之前編譯器就已經(jīng)讀取到了變量和它的屬性m,然后編譯器會在作用域中查找對象是否有m屬性,沒有的話就會生成m屬性</font>
賦值之前讀取當(dāng)obj還有m屬性,所以把他添加到內(nèi)存里面,因?yàn)樾枰却疫呝x值完成所以暫時(shí)指定為null
從右側(cè)開始賦值,即執(zhí)行obj = {n: 2}, '=' 賦值就相當(dāng)于new Object()的語法糖所以新創(chuàng)建了一塊內(nèi)存空間
賦值到左側(cè)的時(shí)候m的屬性值指向了obj的新內(nèi)存地址
這個(gè)時(shí)候我們在測試一下
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}}
看來上述的三步分解是正確的
但是實(shí)際開發(fā)中還是要謹(jǐn)慎使用連等,避免造成不必要的麻煩