挖掘Chrome Console的小秘密

SP_lyu关注
2018.09.15 18:25:32字数 1,697阅读 917

控制台应该是大多数前端开发人员日常开发调试离不开的神器。然而控制台仍有很多不为人知的属性及方法,能让你更爽地使用,当然也包括了一些隐藏的深坑(console.log对象打印bug)...
* 本文探讨的是chrome开发工具中的控制台,其他浏览器也许存在不同的表现,此文不涉猎

Try it first!

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

!(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);
})();

可以看到,一个充满色彩的马里奥出现在了控制台,主要是使用了以下命令实现:

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

*当然这里面还有到了其他的trick处理方式,详情请看作者链接

控制台进阶玩法

从上述的例子可以看出,控制台还有很多我们不知道的进阶玩法,如输出更好的格式,利用一些trick,使得我们的调试更具效率。

Console API

在控制台中输入console.可以看出,console中有很多方法可以调用,网上已有很多资源说明,此次仅提及几个比较有用的API

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

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

  • 使用逗号分隔,传入多个参数输出
    输出时会将每个逗号自动替换成空格
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 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.
这句话意味着,展开当前的object的时候,控制台才会去计算出这个对象的key-value,再反馈到控制台中显示。
原来使用Console打印的时候,若发现当前需要打印的内容是一个对象,会将其保存下来,在控制台中先输出一个简要的快照(Snapshot),待开发者需要查看其中详细内容时,再点击展开,返回内存中的值。
这个是控制台的一个已知的坑点,有可能设计该功能是为了避免控制台对大对象深复制输出,导致调试过慢,也有可能是为了方便查看原型链上的属性,但这无疑是开发者调试代码时需要避开的问题。
要避免这种调试问题,建议使用JSON.stringify()进行输出调试,而不是直接打印当前对象。

内存泄漏问题

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

参考及拓展

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

console.log对象全部展开的更多相关文章

  1. js调试console.log使用总结图解

    一 实例 打印字符串和对象: 可展开对象查看内部情况: 看一下console对象本身的定义情况: 输出对象情况: utag对象所在文件: 输出对象: 二 Console.log 总结 1   如果你j ...

  2. 【调试】js调试console.log使用总结图解(重要)

    0.介绍 先上图:不知道有多少人发现,在浏览器开发工具的“Console”上的百度首页的关于百度招聘的信息: 今天要给大家介绍的就是是Web前端调试工具中的Console面板,应该说只要是个浏览器就会 ...

  3. javascript 中的console.log和弹出窗口alert

    主要是方便你调式javascript用的.你可以看到你在页面中输出的内容. 相比alert他的优点是: 他能看到结构话的东西,如果是alert,淡出一个对象就是[object object],但是co ...

  4. JavaScript调试技巧之console.log()详解

    JavaScript调试技巧之console.log()详解 对于JavaScript程序的调试,相比于alert(),使用console.log()是一种更好的方式,原因在于:alert()函数会阻 ...

  5. console.log的一个应用 -----用new方法生成一个img对象和document.createElement方法创建一个img对象的区别

    我用两种方法来生成img对象,第一种方法是用new方法,第二种方法是用document.createElement方法. var img1 = new Image(); var img2 = docu ...

  6. jquery对象和javascript对象的console.log结果

    array.push($("div").children("label")); console.log(array); 输出: 这个是jquery对象,如果在选 ...

  7. console.log格式化及console对象

    一.console.log格式化打印 console.log格式化这一用法一般都在个人博客或其他官网上有,当F12查看网页元素时,在控制台(console)那里偶尔会发现一些个性化的输出,感觉很奇特很 ...

  8. [JavaScript] console.log只在查看时才会读取这个打印的对象,并把此刻相关属性和值显示出来

      /** * 写个函数解决console.log只在查看时才会读取这个打印的对象,并把此刻相关属性和值显示出来 * @param arg */ const log = function (...ar ...

  9. console.log 如何打印对象

    问题描述: var obj={a:1,b:2}; console.log(obj); 控制台返回的值是object. 解决方案: console.log(JSON.stringify(obj))

随机推荐

  1. 静态库&动态库&导入库

    我遇到的问题 先贴一个StackOverflow上的问题 上面的问题让我知道了更多动态库的知识. 我需要使用一个声音库(irrKlang)为2d游戏提供声音,我使用的编译器是mingw-w64,但是i ...

  2. 1.python数据类型详解

    python数据类型分类 1).数值型:整数型(int).浮点型(float).布尔型(bool 取值:True.False) 2).容器类型 : 字符串型(str).列表(list).元祖(tupl ...

  3. docker - apt-get更换国内源解决Dockerfile构建速度过慢

    背景 使用ubuntu镜像一般apt-get源地址都是在国外导致在构建时因为源地址问题导致下载速度极其得慢 在构建中应事先修改apt-get源地址来避免因下载速度过慢导致的构建缓慢问题 方案 在Doc ...

  4. Mysql-分库分区分表

    大数据-分表分区分库问题集:1.分表时两张表的数据都一样么?如果一样,只是降低了表的访问量,但是如果数据多了还是没有提高查询的效率答:分表是对一张表中的数据按照某种规则进行拆分到三张表中,三张表的所有 ...

  5. mac 电脑画图软件相关

    sketchbook 免费但是不太好用 sketch, https://www.newasp.net/soft/327640.html 注意:安装前,请开启任何来源.OS X 10.12 及以上版本请 ...

  6. Java【第二课 扫描仪 & 布尔数据类型】

    一.Java扫描仪 为了更加方便的理解,我先将逻辑框图 这个有点像C语言的scan()的用法 import java.util.Scanner; //导入扫描仪 public class demo{ ...

  7. wfuzz的使用

    用于模糊测试,测试过滤字符 转载:https://www.secpulse.com/archives/81560.html https://www.freebuf.com/sectool/173746 ...

  8. install multiple versions of CUDA

    https://www.pugetsystems.com/labs/hpc/How-To-Install-CUDA-10-together-with-9-2-on-Ubuntu-18-04-with- ...

  9. PAT (Advanced Level) Practice 1035 Password (20 分)

    To prepare for PAT, the judge sometimes has to generate random passwords for the users. The problem ...

  10. nodeJS菜鸟教程笔记

    http模块 var http = require('http'); // 引入http模块 var url = require('url'); // 引入url模块 var querystring ...