挖掘Chrome Console的小秘密

控制台应该是大多数前端开发人员平常开发调试离不开的神器。然而控制台仍有不少鲜为人知的属性及方法,能让你更爽地使用,固然也包括了一些隐藏的深坑(console.log对象打印bug #feature)...
* 本文探讨的是chrome开发工具中的控制台,其余浏览器也许存在不一样的表现,此文不涉猎
* 对象打印问题在本文的最末尾点击跳转css

Try it first!

开始前,让咱们来造一个马里奥!
打开开发者工具的控制台,将下述代码复制粘贴,而后猛敲回车!html

!(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);
})();
复制代码

能够看到,一个充满色彩的马里奥出如今了控制台 前端

Mario

主要是使用了如下命令实现: console.log('%c','/*css*/');web

*固然这里面还有到了其余的trick处理方式,详情请看做者连接chrome

控制台进阶玩法

从上述的例子能够看出,控制台还有不少咱们不知道的进阶玩法,如输出更好的格式,利用一些trick,使得咱们的调试更具效率。浏览器

Console API

在控制台中输入console.能够看出,console中有不少方法能够调用,网上已有不少资源说明,这次仅说起几个比较有用的APIapp

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

console.log除了常见的将须要输出的结果直接传入第一个参数中,还有如下用法:chrome-devtools

  • 使用逗号分隔,传入多个参数输出
    输出时会将每一个逗号自动替换成空格
console.log('Hello','world!\t','Current Time:',Date.now());
// Hello world! Current Time: 1530694211342
复制代码
  • 使用说明符输出,相似于C++中的print函数
    除了通常的%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});
复制代码

上述代码输出结果见下图: 函数

console.log with format

console.count

写入在同一行使用相同标签调用count()的次数,可用于某些setInterval或者事件重复触发的调试。工具

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 console.trace

输出一条消息,并包含了调用该方法的地方的堆栈信息。区别是error会将消息设置成错误的样式。

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

上述代码输出结果见下图:

console.error

console.time timeEnd

启动一个具备关联标签的新计时器。使用相同标签调用console.timeEnd()时,定时器将中止,通过的时间将显示在控制台中。计时器值精确到亚毫秒。传递到time()timeEnd()的字符串必须匹配,不然计时器不会结束。
可用于分析某段代码的时间消耗。

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

尝试一下,在一个未引入jQueryzepto的页面的控制台中,直接输入$$$会出现什么?

// 直接打开控制台输入
console.log($,$$);
// 输出:
// ƒ $(selector, [startNode]) { [Command Line API] } ƒ $$(selector, [startNode]) { [Command Line API] }
复制代码

能够看到,输出的函数中,包含了[Command Line API]Command Line API是由控制台提供的一系列便捷函数集合,大概的功能有:选择和检查 DOM元素,以可读格式显示数据,中止和启动分析器,以及监控 DOM 事件。
* 注1:此类API仅经过控制台自己获取,在JS代码中带上此类代码会报错。
* 注2:若全局已覆盖了相同名称的方法,则此类方法将被覆盖。

$、$$

$(selector)等同于document.querySelector,一样的,$(selector)等同于document.querySelectorAllCommand Line API只是提供了较快捷的方式便于开发者进行调试。

$0-$4

$0$1$2$3$4命令用做在 Elements 面板中检查的最后五个DOM元素或在 Profiles面板中选择的最后五个JavaScript堆对象的历史参考。$0返回最近一次选择的元素或JavaScript对象,$1返回仅在最近一次以前选择的元素或对象,依此类推。
如下结果是在测试页面上依次点击html标签、head标签、meta标签的结果:

\$0 - \$4

others

此外,还有不少好用的Command Line API,如copydebugmonitorprofile等。能够在Chrome的Command Line API文档中找到他们的使用方法.

控制台的坑

试想一下如下代码在控制台中输出的结果:

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);
复制代码

不难看出,控制台中输出的结果应该以下图:

console with complex object

此时,咱们展开一下第二行与第五行,会发现一个很奇怪的现象:

object expand
展开第二行发现,arr里的长度是5,对象的index值竟然是5!

延时计算问题

定位上述的问题,只须要将鼠标移至行尾的蓝色info标记上,控制台会提示如下内容:
Value below was evaluated just now. #因此这不是bug是feature
这句话意味着,展开当前的object的时候,控制台才会去计算出这个对象的key-value,再反馈到控制台中显示。
使用Console打印的时候,若控制台发现当前须要打印的内容是一个对象,会将其保存下来,先输出一个简要的快照(Snapshot),待开发者须要查看其中详细内容时,再点击展开,返回内存中的值。
这个是控制台的一个已知的坑点,有可能设计该功能是为了不控制台对大对象深复制输出,致使调试过慢,也有多是为了方便查看原型链上的属性,但这无疑是开发者调试代码时须要避开的问题。
要避免这种调试问题,建议使用JSON.stringify()进行输出调试,而不是直接打印当前对象。

内存泄漏问题

上面提到,使用Console打印对象时,会将这个对象的引用保存下来。因为开发者工具在浏览器中默认开启,且默认了“开发者以后须要查看该对象”的行为,就会致使在Console中引入的对象是不会进入GC(垃圾回收)逻辑中的,这就引起了内存泄漏问题。 要避免内存泄漏问题,须要将开发环境与线上环境进行分离,线上环境中避免产生控制台打印的语句,亦能够在项目打包时,将ESLint中的no-console的开关打开。

参考及拓展

medium.com/@aristretto…
developers.google.com/web/tools/c…
stackoverflow.com/questions/1…

相关文章
相关标签/搜索