挖掘Chrome Console的小秘密

控制臺應(yīng)該是大多數(shù)前端開發(fā)人員日常開發(fā)調(diào)試離不開的神器。然而控制臺仍有很多不為人知的屬性及方法,能讓你更爽地使用,當(dāng)然也包括了一些隱藏的深坑(console.log對象打印bug)...
* 本文探討的是chrome開發(fā)工具中的控制臺,其他瀏覽器也許存在不同的表現(xiàn),此文不涉獵

Try it first!

開始前,讓我們來造一個(gè)馬里奧!
打開開發(fā)者工具的控制臺,將下述代碼復(fù)制粘貼,然后猛敲回車!

!(navigator.userAgent.toLowerCase().indexOf('chrome') > -1) ? null : (function() {
    var args = [],  eightBitHack = [], coordinates = ["41n8r2", "42t3wu", "449u8a", "4h4014", "4h2c4y", "4g6ia1", "4286dm", "447r6w", "4fudcv", "61z2xp", "70rmyd", "71sfq1", "6zgplp", "42spfv", "4frvnp", "61wzpd"];
    for (var row = coordinates.length; row--;) {
        var decompressedRow = parseInt(coordinates[row], 36).toString(5).split('');
        coordinates[row] = decompressedRow.splice(1, decompressedRow.length-1);
        for (var cell = coordinates[row].length; cell--;) {
            var dot = parseInt(coordinates[row][cell]);
            var color = dot === 4 ? '#ecd585' : dot === 3 ? '#e1c25b' : dot === 2 ? '#805936' : dot ? '#ec2733' : '#fff';
            args.unshift("border: 8px solid color;".replace('color', color));
            eightBitHack.unshift("%c");
        }
        eightBitHack.unshift("\n");
    }
    eightBitHack.push("%c\n\n\n", "\nIt's me, Mario!", "\nmade by %chttps://twitter.com/aristretto");
    args.push("font-weight: bold;", "font-weight: bold; color: teal;");
    args.unshift(eightBitHack.join(''));
    console.log.apply(console, args);
})();

可以看到,一個(gè)充滿色彩的馬里奧出現(xiàn)在了控制臺,主要是使用了以下命令實(shí)現(xiàn):

console.log('%c','/*css*/');

Mario

*當(dāng)然這里面還有到了其他的trick處理方式,詳情請看作者鏈接

控制臺進(jìn)階玩法

從上述的例子可以看出,控制臺還有很多我們不知道的進(jìn)階玩法,如輸出更好的格式,利用一些trick,使得我們的調(diào)試更具效率。

Console API

在控制臺中輸入console.可以看出,console中有很多方法可以調(diào)用,網(wǎng)上已有很多資源說明,此次僅提及幾個(gè)比較有用的API

console.log(object[,object,...])

console.log除了常見的將需要輸出的結(jié)果直接傳入第一個(gè)參數(shù)中,還有以下用法:

  • 使用逗號分隔,傳入多個(gè)參數(shù)輸出
    輸出時(shí)會(huì)將每個(gè)逗號自動(dòng)替換成空格
console.log('Hello','world!\t','Current Time:',Date.now());
// Hello world! Current Time: 1530694211342
  • 使用說明符輸出,類似于C++中的print函數(shù)
    除了一般的%s(字符串)、%i``%d(均為整型)、%f外,還支持%c(樣式)、%o(DOM元素)、%O(JavaScript對象)輸出
console.log('Hello world!\t%s: %i','Current Time',Date.now());
console.log("normal text,%c large blue text,%c white text with black background ", "color: blue; font-size: x-large","color:white;background:black;");
console.log('%o\n%O',document,{a:1,b:2,c:3});

上述代碼輸出結(jié)果見下圖:


console.log with format

console.count

寫入在同一行使用相同標(biāo)簽調(diào)用count()的次數(shù),可用于某些setInterval或者事件重復(fù)觸發(fā)的調(diào)試。

const fn = function(name){
    console.count(name);
};
fn('Bob');      // Bob: 1
fn('John');     // John: 1
fn('Bob');      // Bob: 2
fn('Bob');      // Bob: 3

console.error trace

輸出一條消息,并包含了調(diào)用該方法的地方的堆棧信息。區(qū)別是error會(huì)將消息設(shè)置成錯(cuò)誤的樣式。

(()=>{
    const fn1 = (fn)=>{
        fn();
    };
    const fn2 = ()=>{
        console.trace('Target Not Found');
        console.error('Target Not Found');
    };
    fn1(fn2);
})();

上述代碼輸出結(jié)果見下圖:


console.error

console.time timeEnd

啟動(dòng)一個(gè)具有關(guān)聯(lián)標(biāo)簽的新計(jì)時(shí)器。使用相同標(biāo)簽調(diào)用console.timeEnd()時(shí),定時(shí)器將停止,經(jīng)過的時(shí)間將顯示在控制臺中。計(jì)時(shí)器值精確到亞毫秒。傳遞到time()timeEnd()的字符串必須匹配,否則計(jì)時(shí)器不會(huì)結(jié)束。
可用于分析某段代碼的時(shí)間消耗。

console.time('test');
for(let i = 0; i < 100000000; i++){}
console.timeEnd('test');
// 輸出:
// test: 122.71923828125ms

others

此外,還有很多好用的Console API,如console.tableconsole.groupconsole.assert等。可以在Chrome的Console API文檔中找到他們的使用方法.

Command Line API

嘗試一下,在一個(gè)未引入jQueryzepto的頁面的控制臺中,直接輸入$$$會(huì)出現(xiàn)什么?

// 直接打開控制臺輸入
console.log($,$$);
// 輸出:
// ? $(selector, [startNode]) { [Command Line API] } ? $$(selector, [startNode]) { [Command Line API] }

可以看到,輸出的函數(shù)中,包含了[Command Line API]Command Line API 是由控制臺提供的一系列便捷函數(shù)集合,大概的功能有:選擇和檢查 DOM 元素,以可讀格式顯示數(shù)據(jù),停止和啟動(dòng)分析器,以及監(jiān)控 DOM 事件。
* 注1:此類API僅通過控制臺本身獲取,在JS代碼中帶上此類代碼會(huì)報(bào)錯(cuò)。
* 注2:若全局已覆蓋了相同名稱的方法,則此類方法將被覆蓋。

$、$$

$(selector)等同于document.querySelector,同樣的,$(selector)等同于document.querySelectorAllCommand Line API只是提供了較快捷的方式便于開發(fā)者進(jìn)行調(diào)試。

$0-$4

$0$1$2$3$4命令用作在 Elements 面板中檢查的最后五個(gè)DOM元素或在 Profiles面板中選擇的最后五個(gè)JavaScript堆對象的歷史參考。$0返回最近一次選擇的元素或JavaScript對象,$1返回僅在最近一次之前選擇的元素或?qū)ο螅来祟愅啤?br> 以下結(jié)果是在測試頁面上依次點(diǎn)擊html標(biāo)簽、head標(biāo)簽、meta標(biāo)簽的結(jié)果:

$0 - $4

others

此外,還有很多好用的Command Line API,如copydebugmonitorprofile等。可以在Chrome的Command Line API文檔中找到他們的使用方法.

控制臺的坑

試想一下以下代碼在控制臺中輸出的結(jié)果:

const fn = function(length){
    const o = {
        arr: [],
        key1: 'test',
        key2: 'test',
        key3: 'test',
        key4: 'test',
        key5: 'test',
        index: 0
    };
    console.log(JSON.stringify(o));
    console.log(o);
    console.log('Handling data');
    for(let i = 0; i < length; i++){
        o.arr.push(i);
    }
    o.index = length;
    console.log(JSON.stringify(o));
    console.log(o);
};
fn(5);

不難看出,控制臺中輸出的結(jié)果應(yīng)該如下圖:


console with complex object

此時(shí),我們展開一下第二行與第五行,會(huì)發(fā)現(xiàn)一個(gè)很奇怪的現(xiàn)象:


object expand

展開第二行發(fā)現(xiàn),arr里的長度是5,對象的index值居然是5!

延時(shí)計(jì)算

定位上述的問題,只需要將鼠標(biāo)移至行尾的藍(lán)色info標(biāo)記上,控制臺會(huì)提示以下內(nèi)容:
Value below was evaluated just now.
這句話意味著,展開當(dāng)前的object的時(shí)候,控制臺才會(huì)去計(jì)算出這個(gè)對象的key-value,再反饋到控制臺中顯示。
原來使用Console打印的時(shí)候,若發(fā)現(xiàn)當(dāng)前需要打印的內(nèi)容是一個(gè)對象,會(huì)將其保存下來,在控制臺中先輸出一個(gè)簡要的快照(Snapshot),待開發(fā)者需要查看其中詳細(xì)內(nèi)容時(shí),再點(diǎn)擊展開,返回內(nèi)存中的值。
這個(gè)是控制臺的一個(gè)已知的坑點(diǎn),有可能設(shè)計(jì)該功能是為了避免控制臺對大對象深復(fù)制輸出,導(dǎo)致調(diào)試過慢,也有可能是為了方便查看原型鏈上的屬性,但這無疑是開發(fā)者調(diào)試代碼時(shí)需要避開的問題。
要避免這種調(diào)試問題,建議使用JSON.stringify()進(jìn)行輸出調(diào)試,而不是直接打印當(dāng)前對象。

內(nèi)存泄漏問題

上面提到,使用Console打印對象時(shí),會(huì)將這個(gè)對象的引用保存下來。由于開發(fā)者工具在瀏覽器中默認(rèn)開啟,且默認(rèn)了“開發(fā)者之后需要查看該對象”的行為,就會(huì)導(dǎo)致在Console中引入的對象是不會(huì)進(jìn)入GC(垃圾回收)邏輯中的,這就引發(fā)了內(nèi)存泄漏問題。
要避免內(nèi)存泄漏問題,需要將開發(fā)環(huán)境與線上環(huán)境進(jìn)行分離,線上環(huán)境中避免產(chǎn)生控制臺打印的語句,亦可以在項(xiàng)目打包時(shí),將ESLint中的no-console的開關(guān)打開。

參考及拓展

https://medium.com/@aristretto/8-bit-fun-with-console-log-7905d87e8b9d
https://developers.google.com/web/tools/chrome-devtools/
https://stackoverflow.com/questions/12996129/memory-leak-when-logging-complex-objects

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,363評論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,497評論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,305評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,962評論 1 311
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,727評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,193評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,257評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,411評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,945評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,777評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,978評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,519評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,216評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,657評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,960評論 2 373

推薦閱讀更多精彩內(nèi)容