關於valueOf執行順序問題?

function test() {

var fn = function () {}

fn.valueOf = function () {
console.log("before");
return "after"
}

return fn
}

console.log(test())
// after
// before

上述代碼中 最後的輸入結果竟然是先輸入"after",在輸入"before"。這是不是太詭異了點,沒法接受啊! 各位大神賜教!


TL;DR

Chrome 開發者工具控制台的原因。第一行輸出的 element 是控制台先創建好的,但是內容(function after)是在輸出了第二行(before)之後才更新的。

0x00

題主的代碼在 Chrome 開發者工具控制台里確實會輸出

function after
before
undefined

(最後一行是 console.log() 的返回值)

但是你會發現,不論是在 Firefox 下還是 Node.js 環境里,都沒法重現。

0x01

第一行輸出的

function after

其實是 test() 里創建的 fn(),顯然是調用了 fn.valueOf() 出來的結果,後面輸出的 before 也說明了這一點。但是,並不是你的代碼「主動」調用了 fn.valueOf()。

如果試著改成

f = () =&> {};
f.valueOf = () =&> {
console.log("before");
return "after";
};
console.log(f.valueOf());

或者

console.log(f + "");

就會發現它輸出了

before
after
undefined

換句話說,這個調用是由 Chrome(的開發者工具控制台)而不是你的代碼導致的。

0x02

其實控制台是一個 ConsoleView,每一行輸出是一個 ConsoleViewMessage。ConsoleView 實現了 itemCount() 和 itemElement() 供 UI.ViewportControl 來更新界面。

簡單來說,UI.ViewportControl 根據 ConsoleView 里的 _visibleViewMessages 數組把每一條 ConsoleViewMessage 更新到界面上去。

在調用 _appendMessageToEnd(viewMessage) 的時候,先把 viewMessage push 進了這個數組。然而,所有的 DOM 對象都是第一次用到的時候才創建的。只有在 UI.ViewportControl#_fullViewportUpdate() 的時候才會真正地調用 viewportElement.element() 來創建 ConsoleViewMessage 的 element,從而去做顯示的格式化:

https://github.com/nwjs/chromium.src/blob/26eb402c48007c2fcb6321b4c038a295724f71dd/third_party/WebKit/Source/devtools/front_end/ui/ViewportControl.js#L392

第一次調用 ConsoleViewMessage#toMessageElement() 的時候調用了 ConsoleViewMessage#updateMessageElement():

https://github.com/nwjs/chromium.src/blob/26eb402c48007c2fcb6321b4c038a295724f71dd/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js#L970

一路跟進去,發現調用了 ConsoleViewMessage#_parameterToRemoteObject(),從而調用 RuntimeModel#createRemoteObject() 創建了一個 RemoteObjectImpl。

RemoteObjectImpl 的構造函數里在構造 this._description 的時候有這麼一句:

if (!this._description (typeof value !== "object" || value === null))
this._description = value + "";

fn.valueOf() 就是在這裡被調用的。(不太確定,需要編譯一波看看。)

最終一路傳回到 ConsoleViewMessage#_formatParameterAsFunction(),被 append 了進去:

https://github.com/nwjs/chromium.src/blob/26eb402c48007c2fcb6321b4c038a295724f71dd/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js#L555

EOF.


chrome 裡面的 console.log 是非同步的


你的執行環境是什麼都沒法復現


推薦閱讀:

谷歌地圖的顯示方式是如何做到的?
Facebook 首頁都使用了哪些技術提高訪問速度?
怎麼讓input元素的顯示值和value值不一樣?
如果個人技能與如圖所示的技能差不多,可以找到一份多少薪水的工作?

TAG:前端開發 | 程序員 | JavaScript | 前端工程師 | 面試問題 |