挖掘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. 逆战:微信小程序开发(二)

    一.常用组件 在上一个章节中讲解了封装请求数据的模块,在此处请求轮播图的数据 1.首页轮播图数据的请求以及渲染 1.1 轮播图数据的请求 pages/home/home.js import { req ...

  2. js内置对象的常用属性和方法(Array | String | Date | Math)

    js内置对象:Array  String  Math  Date <!DOCTYPE html> <html lang="en"> <head> ...

  3. #AcWing系列课程Level-2笔记——4. 浮点数二分算法

    浮点数二分算法 编写浮点数二分,记住下面的思路,代码也就游刃有余了! 1.首先找到数组的中间值,mid=(left+right)>>1,区间[left, right]被划分成[left, ...

  4. Selenium实战(七)——自动发送邮件

    SMPT(Simple Mail Transfer Protocol)简单邮件传输协议,是一组由源地址到目的地址传送邮件的规则,可以控制信件的中转方式.Python的smptlib模块提供了简单的AP ...

  5. MySQL 8 服务器日志

    错误日志: 启动.运行.停止 mysqld(MySQL Server) 遇到的问题 通用查询日志: 建立客户端连接和从客户端接收的语句 二进制日志: 更改数据的语句(也用于复制) 中继日志: 从复制m ...

  6. srpingboot web - 启动(3) 监听器

    接上一篇 一. getRunListeners() 在run() 方法中调用了 getRunListeners(args) 方法, 先看一下这个方法干了什么 private SpringApplica ...

  7. WSL Ubuntu 安装MongoDb 4.0导入公钥时遇到一个坑 (转)

    WSL Ubuntu 安装MongoDb 4.0导入公钥时遇到一个坑 一路坑啊~~~网上的密钥都不对????  不应该啊 源中默认是MongoDb 3.x 但是我想用4.0,然后按照mongodb官方 ...

  8. C语言递归之二叉树的最小深度

    题目描述 给定一个二叉树,找出其最小深度. 最小深度是从根节点到最近叶子节点的最短路径上的节点数量. 说明: 叶子节点是指没有子节点的节点. 示例 输入:[3,9,20,null,null,15,7] ...

  9. python常见函数积累

    shape() 返回数组或者数据框有多少行或者多少列 import numpy as np x = np.array([[1,2,5],[2,3,5],[3,4,5],[2,3,6]]) #输出数组的 ...

  10. PAT (Basic Level) Practice (中文)1022 D进制的A+B (20 分)

    输入两个非负 10 进制整数 A 和 B (≤),输出 A+B 的 D (1)进制数. 输入格式: 输入在一行中依次给出 3 个整数 A.B 和 D. 输出格式: 输出 A+B 的 D 进制数. 输入 ...