在工作中遇到,使用console.log()輸出對象信息時,出現輸出的信息跟自己想的不一樣的問題,導致調試bug時,思路走偏。
當時參考了別人的issues已經講的很清楚了。
這里自己再記錄一下
問題描述:
即使我直接在賦值語句
const obj = {age: 20}后面緊跟console.log(obj),
在瀏覽器的控制台,看到的age字段,也不一定是20。因為,如果在后面的代碼中,修改了age字段的值,那控制台看到的就不是20了。
比如執行如下代碼:
let obj = {age: 20};
console.log(obj);
obj.age = 30;
得到的輸出如下:

可以看到,不展開obj對象,看到的是我們預期的20,展開對象,看到的卻是30。
如果我們輸出一個字段很多的對象,那必須展開才能看到屬性值,就會被非預期的屬性值誤導。
原因分析:
- 不展開對象看時,console.log()是按照代碼執行順序,同步地輸出了對象當時的快照。所以我們看到的是預期的值。
- 展開對象時,它其實是重新去內存中讀取對象的屬性值,此時對象屬性已被更改,所以展開對象后,可能看到的不是預期值了。
瀏覽器或者開發者工具(F12)為什么出現這種情況?
這個問題,在《你不知道的javascript中卷》第二部分異步和性能1.1節一部控制台部分有提及:
There is no specification or set of requirements around how the console.* methods work -- they are not officially part of JavaScript, but are instead added to JS by the hosting environment (see the Types & Grammar title of this book series).
So, different browsers and JS environments do as they please, which can sometimes lead to confusing behavior.
In particular, there are some browsers and some conditions that console.log(..) does not actually immediately output what it's given. The main reason this may happen is because I/O is a very slow and blocking part of many programs (not just JS). So, it may perform better (from the page/UI perspective) for a browser to handle console I/O asynchronously in the background, without you perhaps even knowing that occurred.
翻譯:
並沒有什么規范或一組需求指定console.* 方法族如何工作——它們並不是JavaScript 正式的一部分,而是由宿主環境(請參考本書的“類型和語法”部分)添加到JavaScript 中的。因此,不同的瀏覽器和JavaScript 環境可以按照自己的意願來實現,有時候這會引起混淆。
尤其要提出的是,在某些條件下,某些瀏覽器的console.log(..) 並不會把傳入的內容立即輸出。出現這種情況的主要原因是,在許多程序(不只是JavaScript)中,I/O 是非常低速的阻塞部分。所以,(從頁面/UI 的角度來說)瀏覽器在后台異步處理控制台I/O 能夠提高性能,這時用戶甚至可能根本意識不到其發生。
結論
console.log()打印出來的內容並不是一定百分百可信的內容。一般對於基本類型number、string、boolean、null、undefined的輸出是可信的。但對於Object等引用類型來說,則就會出現上述異常打印輸出。
建議
- 盡量不要直接輸出對象,先將對象序列化
JSON.stringify()為字符串再輸出 - 最好使用打斷點(debugger)的方式來調試。
