摘要:有這樣一個熱門問題其實這個問題很好理解,關鍵要弄清下面兩個知識點引擎對賦值表達式的處理過程賦值運算的右結合性一賦值表達式形如的表達式稱為賦值表達式。賦值表達式是右結合的。
有這樣一個熱門問題:
var a = {n: 1}; var b = a; a.x = a = {n: 2}; alert(a.x); // --> undefined alert(b.x); // --> {n: 2}
其實這個問題很好理解,關鍵要弄清下面兩個知識點:
JS引擎對賦值表達式的處理過程
賦值運算的右結合性
一. 賦值表達式形如
A = B
的表達式稱為賦值表達式。其中A和B又分別可以是表達式。B可以是任意表達式,但是A必須是一個左值。
所謂左值,就是可以被賦值的表達式,在ES規范中是用內部類型引用(Reference)描述的。例如:
表達式foo.bar可以作為一個左值,表示對foo這個對象中bar這個名稱的引用;
變量email可以作為一個左值,表示對當前執行環境中的環境記錄項envRec中email這個名稱的引用;
同樣地,函數名func可以做左值,然而函數調用表達式func(a, b)不可以。
那么JS引擎是怎樣計算一般的賦值表達式 A = B的呢?簡單地說,按如下步驟:
計算表達式A,得到一個引用refA;
計算表達式B,得到一個值valueB;
將valueB賦給refA指向的名稱綁定;
返回valueB。
二. 結合性所謂結合性,是指表達式中同一個運算符出現多次時,是左邊的優先計算還是右邊的優先計算。
賦值表達式是右結合的。這意味著:
A1 = A2 = A3 = A4
等價于
A1 = (A2 = (A3 = A4))三. 連等的解析
好了,有了上面兩部分的知識。下面來看一下JS引擎是怎樣運算連等賦值表達式的。
以下面的式子為例:
Exp1 = Exp2 = Exp3 = Exp4
首先根據右結合性,可以轉換成
Exp1 = (Exp2 = (Exp3 = Exp4))
然后,我們已經知道對于單個賦值運算,JS引擎總是先計算左邊的操作數,再計算右邊的操作數。所以接下來的步驟就是:
計算Exp1,得到Ref1;
計算Exp2,得到Ref2;
計算Exp3,得到Ref3;
計算Exp4,得到Value4。
現在變成了這樣的:
Ref1 = (Ref2 = (Ref3 = Value4))
接下來的步驟是:
將Value4賦給Exp3;
將Value4賦給Exp2;
將Value4賦給Exp1;
返回表達式最終的結果Value4。
注意:這幾個步驟體現了右結合性。
總結一下就是:
四. 問題的解決先從左到右解析各個引用,然后計算最右側的表達式的值,最后把值從右到左賦給各個引用。
現在回到文章開頭的問題。
首先前兩個var語句執行完后,a和b都指向同一個對象{n: 1}(為方便描述,下面稱為對象N1)。然后來看
a.x = a = {n: 2};
根據前面的知識,首先依次計算表達式a.x和a,得到兩個引用。其中a.x表示對象N1中的x,而a相當于envRec.a,即當前環境記錄項中的a。所以此時可以寫出如下的形式:
[[N1]].x = [[encRec]].a = {n: 2};
其中,[[]]表示引用指向的對象。
接下來,將{n: 2}賦值給[[encRec]].a,即將{n: 2}綁定到當前上下文中的名稱a。
接下來,將同一個{n: 2}賦值給[[N1]].x,即將{n: 2}綁定到N1中的名稱x。
由于b仍然指向N1,所以此時有
b <=> N1 <=> {n: 1, x: {n: 2}}
而a被重新賦值了,所以
a <=> {n: 2}
并且
a === b.x五. 最后的最后
如果你明白了上面所有的內容,應該會明白a.x = a = {n:2};與b.x = a = {n:2};是完全等價的。因為在解析a.x或b.x的那個時間點。a和b這兩個名稱指向同一個對象,就像C++中同一個對象可以有多個引用一樣。而在這個時間點之后,不論是a.x還是b.x,其實早就不存在了,它已經變成了那個內存中的對象.x了。
最后用一張圖表示整個表達式的運算過程:
六. 參考文檔11.13.1 Simple Assignment ( = )
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/78389.html
摘要:引擎對堆內存中的對象進行分代管理新生代存活周期較短的對象,如臨時變量字符串等。內存泄漏對于持續運行的服務進程,必須及時釋放不再用到的內存。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第一期,本周的主題是調用堆棧,今天是第4天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進階計劃...
摘要:有三個重要組成部分和。參考小結函數中的是由調用函數的方式決定的。構造函數中的當構造函數通過操作符來調用時,表示正在創建的對象。情況沒有明確作用對象的情況下,通常為全局對象例如函數的回調函數,它的就是全局對象。 一. this的來源 this是JavaScript的關鍵字,它最初應該是從Java、C++等面向對象的語言中借鑒來的。 比如,在Java中沒有函數只有方法,this只能用在類的...
摘要:既然是屬性,當然可以賦值。然而這三個屬性又是不可寫的屬性,即它們的的內部特性為,所以賦值無效。因為嚴格模式下,禁止給對象的只讀屬性賦值。雖然號稱是這種原始類型可以取的唯一值,然而輸出參考文檔 提出問題 如下代碼: undefined = 123; null = 123; // 報錯:Uncaught Reference Error 第一條語句可以執行,盡管賦值并沒有成功;第二條語句報錯...
摘要:本文最早為雙十一而作,原標題雙大前端工程師讀書清單,以付費的形式發布在上。發布完本次預告后,捕捉到了一個友善的吐槽讀書清單也要收費。這本書便從的異步編程講起,幫助我們設計快速響應的網絡應用,而非簡單的頁面。 本文最早為雙十一而作,原標題雙 11 大前端工程師讀書清單,以付費的形式發布在 GitChat 上。發布之后在讀者圈群聊中和讀者進行了深入的交流,現免費分享到這里,不足之處歡迎指教...
摘要:本文最早為雙十一而作,原標題雙大前端工程師讀書清單,以付費的形式發布在上。發布完本次預告后,捕捉到了一個友善的吐槽讀書清單也要收費。這本書便從的異步編程講起,幫助我們設計快速響應的網絡應用,而非簡單的頁面。 本文最早為雙十一而作,原標題雙 11 大前端工程師讀書清單,以付費的形式發布在 GitChat 上。發布之后在讀者圈群聊中和讀者進行了深入的交流,現免費分享到這里,不足之處歡迎指教...
閱讀 2016·2021-11-12 10:36
閱讀 1865·2021-11-09 09:49
閱讀 2591·2021-11-04 16:12
閱讀 1144·2021-10-09 09:57
閱讀 3235·2019-08-29 17:24
閱讀 1909·2019-08-29 15:12
閱讀 1272·2019-08-29 14:07
閱讀 1285·2019-08-29 12:53