<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [TOC] 有這樣一個熱門問題: ~~~ 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`的呢?簡單地說,按如下步驟: 1. 計算表達式A,得到一個引用`refA`; 2. 計算表達式B,得到一個值`valueB`; 3. 將`valueB`賦給`refA`指向的名稱綁定; 4. 返回`valueB`。 # 二. 結合性 所謂結合性,是指表達式中同一個運算符出現多次時,是左邊的優先計算還是右邊的優先計算。 賦值表達式是右結合的。這意味著: ~~~ A1 = A2 = A3 = A4 ~~~ 等價于 ~~~ A1 = (A2 = (A3 = A4)) ~~~ # 三. 連等的解析 好了,有了上面兩部分的知識。下面來看一下JS引擎是怎樣運算連等賦值表達式的。 以下面的式子為例: ~~~ Exp1 = Exp2 = Exp3 = Exp4 ~~~ 首先根據右結合性,可以轉換成 ~~~ Exp1 = (Exp2 = (Exp3 = Exp4)) ~~~ 然后,我們已經知道對于單個賦值運算,JS引擎總是先計算左邊的操作數,再計算右邊的操作數。所以接下來的步驟就是: 1. 計算Exp1,得到Ref1; 2. 計算Exp2,得到Ref2; 3. 計算Exp3,得到Ref3; 4. 計算Exp4,得到Value4。 現在變成了這樣的: ~~~ Ref1 = (Ref2 = (Ref3 = Value4)) ~~~ 接下來的步驟是: 1. 將Value4賦給Exp3; 2. 將Value4賦給Exp2; 3. 將Value4賦給Exp1; 4. 返回表達式最終的結果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`了。 最后用一張圖表示整個表達式的運算過程: ![](https://box.kancloud.cn/5ebc07896c828056f4152955fd9a91f5_435x329.png) # 連等與var ~~~ (function (){ var a = 20 var b = c = a })() alert(c) // 20 ~~~ # 更新 事實上,解析器在接受到`a = a.x = {n:2}`這樣的語句后,會這樣做: 1. 找到 a 和 a.x 的指針。如果已有指針,那么不改變它。如果沒有指針,即那個變量還沒被申明,那么就創建它,指向 null。 a 是有指針的,指向`{n:1}`;a.x 是沒有指針的,所以創建它,指向 null。 2. 然后把上面找到的指針,都指向最右側賦的那個值,即`{n:2}`。 ![](https://img.kancloud.cn/cf/64/cf64725c9595f066f7c254e67bcd63e3_1670x526.png) # 參考資料 [javascript 連等賦值問題](https://segmentfault.com/q/1010000002637728) [由ES規范學JavaScript(二):深入理解“連等賦值”問題](https://segmentfault.com/a/1190000004224719)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看