在前端開發中,咱們都少不了用console.log
來輸出變量和調試。但是在使用它的過程當中,偶爾也會出現一些讓咱們很費解的行爲,以下圖:前端
是否是很詭異:)node
這個詭異的行爲是怎麼來的呢?其實怪我「斷章取義」了。控制檯上我執行的代碼實際上是:chrome
注意到展開的數組旁邊有一個小i
,將鼠標移動上去,會出現提示文字:數組
Value below was evaluated just now.
簡單翻譯一下就是:下面展現的值,是剛剛解釋執行(evaluated,或者你能夠用你熟悉的eval函數來理解這個單詞)的結果。瀏覽器
這句話該怎麼理解呢?注意到:小i
這個提示僅在咱們展開數組的時候纔會出現,而展開前控制檯上展現的確實是一個空數組[]
。所以咱們能夠將展開先後認爲是這個值的兩個狀態。函數
如今,咱們定位到了這個詭異的行爲是和展開相關的,那麼讓咱們來實驗一下展開這個操做會對log出來的值產生什麼影響呢?咱們將一行一行地在控制檯執行下面三行js代碼:ui
var a = [] console.log(a) a.push(1, 2, 3, 4, 5)
在執行a.push(1)
以前展開[]
,會獲得下面的結果,應該算是一個預期結果:lua
而在執行a.push(1)
以後再展開[]
,就會獲得一開始我給你們看的「詭異」結果了。spa
如今回過頭來看 Value below was evaluated just now.
這句話,其實說的就是,展開後的值,實際上是在你點擊展開小三角的時候,才 「eval
」 出來的。prototype
再看下面一個例子:
圖中的結果,我是在執行了a = [1, 2, 3, 4, 5]
這句話以後才點擊的小三角,然而結果卻沒有變成「詭異」結果的樣子。這是由於後面我更新數組是直接採用變量賦值的方法,至關於修改了變量a的引用,就和變量的引用賦值同樣,是影響不了a以前所引用的數組的。
也就是說,console.log()
在展開時用於eval
的,是變量指向的引用而不是變量自己。
console.log
的這個行爲並非chrome限定,在Firefox和Safari中你都能獲得一樣的行爲。
Firefox:
Safari中因爲console.log
展不開,所以使用console.dir
來展開:
Edge下就不是這樣子了233:
因此若是你不想要這個「詭異」的結果的話,能夠用 Edge 調試哦:)
一個正常的思路是,若是可以讓console.log
直接輸出就是展開的,那麼這個行爲就不會詭異了。
不過很不幸,我沒有找到可以作這件事情的API。不過,咱們能夠藉助console.group
這個方法,本身造一個展開的結構出來。
/** * expandLog * * @desc 自動展開的 console.log,實現參考: * https://stackoverflow.com/questions/10464844/is-there-a-way-to-auto-expand-objects-in-chrome-dev-tools#27610197 * @author leuisken <leuisken@foxmail.com> * @param {Object} obj 須要 log 的對象 */ function expandLog(obj) { if (Array.isArray(obj)) { obj.forEach((value, index) => { console.group(`${index} : ${type(value)}`); expandLog(value); console.groupEnd(); }); } else if (isPlainObject(obj)) { Object.keys(obj) .forEach(key => { const value = obj[key]; console.group(`${key} : ${type(value)}`); expandLog(value); console.groupEnd(); }); } else { console.log(obj); } return; /** * type * * @desc 針對部分常見類型給予更好的輸出方式 * @param {Object} obj 傳入的對象 * @return {string} 類型字符串 */ function type(obj) { const typeofResult = typeof obj; if (typeofResult !== 'object') { return typeofResult; } else if (obj === null) { return 'null'; } else if (Array.isArray(obj)) { return 'Array'; } else if (obj instanceof RegExp) { return 'RegExp'; } else if (obj instanceof Date) { return 'Date'; } return 'Object'; } /** * isPlainObject * * @desc 即:jQuery.isPlainObject * @param {Object} obj 傳入的對象 * @return {boolean} 是否爲 PlainObject */ function isPlainObject(obj) { if (!obj || obj.toString() !== '[object Object]' || obj.nodeType || obj.setInterval ) { return false; } if (obj.constructor && !obj.hasOwnProperty('constructor') && !obj.constructor.prototype.hasOwnProperty('isPrototypeOf') ) { return false; } let key; for (key in obj) {} return key === undefined || obj.hasOwnProperty(key); } }
這裏寫這個方法只是示個意,估計通常也不會有誰這麼作。。其實很無奈,就和console.log
、console.dir
沒有提供默認展開的API同樣,console.group
也沒有提供默認收起的API。。。。
在搜索可否默認展開console.log
結果的時候,在Stack Overflow上無心間搜到了這樣一個結果。
https://stackoverflow.com/que...
原來 chrome 的 console,也有本身的 console 啊。。