糾結的連等賦值

發表於2015-07-12

偶的看到一段有意思的程式碼:

作為一個熱衷於“鑽牛角尖”的人,樓主對這樣的程式碼很感興趣,也不禁陷入了思考。so也不要說寫這樣的程式碼難維護啥的,純粹為了思考邏輯。

首先,這是一個連等賦值,而且賦值的是個物件。如果是基本的JavaScript型別,不存在引用,也就不會有類似的問題,但是邏輯是一樣的。

賦值過程是怎麼樣的呢?以上的翻譯是,b先賦值5,然後(b=5)會返回所賦的值(也就是5),然後再賦值給a,也就是:

所以最初的程式碼,可以修改成:

如果是這樣,那麼以下程式碼有什麼區別:

很明顯,結果不一樣,繼續瞭解下JavaScript的運算順序。

輸出30,我們猜測JavaScript是從左到右運算的(事實也確實如此)。先取出a在記憶體中的值(10),然後執行fn函式,返回20(同時改變了a的值),10+20=30。

如果運算過程中有括號啥的,是不是會“智慧”地改變運算順序呢?

輸出50,還是從左到右,沒有智慧地先運算括號裡的內容,然後改變a的值,再和a相加。這在JavaScript核心中是怎麼實現的?這個我也沒有研究過,但是我知道C++等語言是沒有這麼“智慧”的,可以通過堆疊來模擬,比如簡單計算器

再回頭看這道題,宣告一個變數a,指向一個物件{n: 1},然後執行連等。可以肯定的是,a.x和a指向的是同一塊記憶體,我們從左到右運算,a.x實際操作的是a指向的物件,發現沒有x這個key,那麼就會自動新增,它的值等待右邊的運算結果。然後a重新引用了一個物件,並且之前的{n:1}這個物件新的key(x)的value也引用到同一個物件上。大概過程如下圖,過程2我把它理解為等待,等待過程3中a的運算結果。

如果要說的稍微“專業”一點,連等是先確定所有變數的指標,再讓指標指向那個賦值

事實上,解析器在接受到?a.x = a = {n:2}?這樣的語句後,會這樣做:

  1. 找到 a 和 a.x 的指標。如果已有指標,那麼不改變它。如果沒有指標,即那個變數還沒被申明,那麼就建立它,指向 null。
    a 是有指標的,指向?{n:1};a.x 是沒有指標的,所以建立它,指向 null。
  2. 然後把上面找到的指標,都指向最右側賦的那個值,即?{n:2}

如果理解了,試試這道題吧:

 

參考:

  1. Operator_Precedence
  2. javascript 連等賦值問題

相關文章