目录
- 00 延伸科普
- 01 不同级别的基础信息打印
- 02 列表型的数据打印成表格
- 2.1 打印单一数据类型
- 2.2 打印复合的参数类型
- 2.3 控制显示的列
- 03 打印某个操作的时长
- 04 给打印编组
- 05 堆栈跟踪
- 5.1 示例一:
- 5.2 示例二:
- 06 打印花里胡哨
- 6.1 样式占位符
- 6.2 ASCII Art
00 延伸科普
Console
对象所提供的 console.*(...)
这样的方法,其实是宿主环境(比如:浏览器、NodeJS 等)提供的用于控制台调试的,它并不是 JavaScript 正式语法的一部分。
它本质上是一个 I/O 操作,但是又不是简单意义上的宏任务,宿主环境的区别会导致 console.*(...)
方法有一定细微的差别,在某些条件下,某些浏览器并不会把传入的内容立即输出。至于到底什么时候控制台 I/O 会延迟,这是一个不确定的问题。
所以调试时,不要盲目相信 console
的输出,特别是打印引用类型时。比如以下代码:
const obj = { a: 1 } | |
console.log(obj) | |
obj.b = 2 |
输出如下:
看着好像没问题,但是这里的 {a: 1}
,其实是 obj
对象的快照。把它展开,就会发现问题所在,在打印 obj
的那一刻,理应不存在属性 b
:
如果非要用 console.*(...)
方法做一些细致的调试,可以在打印引用对象或数组时进行序列化+反序列化,防止疑问产生:
const obj = { a: 1 } | |
console.log(JSON.parse(JSON.stringify(obj))) | |
obj.b = 2 |
01 不同级别的基础信息打印
// 打印内容的通用方法 | |
console.log('普通信息') | |
// 打印一条资讯类说明信息 | |
console.info('资讯类说明信息') | |
// 打印一条警告信息 | |
console.warn('警告信息') | |
// 打印一条错误信息 | |
console.error('错误信息') | |
// 打印一条 debug 级别的消息。控制台配置为显示调试输出时才显示该消息 | |
console.debug('调试信息') |
不同级别的信息在控制台会被标记为不同的颜色,其中 log
和 info
表现相同。
02 列表型的数据打印成表格
console.table()
可以将列表型的数据打印成表格,这里的列表型数据指的是数组或者对象。
表格的第一列是 index
。如果数据 data
是一个数组,那么这一列的单元格的值就是数组的索引。如果数据是一个对象,那么它们的值就是各对象的属性名称。
语法:
console.table(data [, columns])
data
必须,且必须是一个数组或者是一个对象columns
可选,需要显示的列的名称的数组。如果没有columns
参数,则会打印所有列。
点击每列的顶部标签,可以让表格排序。
2.1 打印单一数据类型
- 打印一个由字符串组成的数组
console.table(['哈哈', '嘿嘿', '嘻嘻'])
- 打印一个属性值是字符串的对象
function Person(firstName, lastName) { | |
this.firstName = firstName | |
this.lastName = lastName | |
} | |
const me = new Person('小错', '王') | |
console.table(me) |
2.2 打印复合的参数类型
如果需要打印的元素在一个数组中,或者需要打印的属性在一个对象,并且他们本身就是一个数组或者对象,则将会把这个元素显示在同一行,每个元素占一列。
- 打印一个二元数组
const people = [ ['张三', '李四'], | |
['张龙', '赵虎'], | |
['王二', '麻子'] | |
] | |
console.table(people) |
- 打印一个包含对象的数组
function Person(firstName, lastName) { | |
this.firstName = firstName | |
this.lastName = lastName | |
} | |
const zhangsan = new Person('三', '张') | |
const lisi = new Person('四', '李') | |
const wanger = new Person('二', '王') | |
console.table([zhangsan, lisi, wanger]) |
如果数组包含对象,则列标签是对象的属性名。
- 打印一个属性名是对象的对象
function Person(firstName, lastName) { | |
this.firstName = firstName | |
this.lastName = lastName | |
} | |
const family = {} | |
family.mother = new Person('羊', '刘') | |
family.father = new Person('龙', '张') | |
family.daughter = new Person('三', '张') | |
console.table(family) |
如果对象的属性为对象,打印出来的 index
是外层对象的属性名。
2.3 控制显示的列
function Person(firstName, lastName) { | |
this.firstName = firstName | |
this.lastName = lastName | |
} | |
const liuyang = new Person('羊', '刘') | |
const zhanglong = new Person('龙', '张') | |
const zhangsan = new Person('三', '张') | |
const family = {} | |
family.mother = liuyang | |
family.father = zhanglong | |
family.daughter = zhangsan | |
console.table([liuyang, zhanglong, zhangsan], ['firstName']) | |
console.table(family, ['lastName']) |
03 打印某个操作的时长
可以通过 console.time
启动一个计时器来跟踪某一个操作的占用时长。
语法:
console.time(timerName)
timerName
每一个计时器必须填写的唯一的名字
通过 console.timeEnd
结束特定的计时器,并打印其从开始到结束所用的毫秒时间。
语法:
console.timeLog(timerName)
示例:
console.time('answer time') | |
alert('点击继续') | |
console.timeLog('answer time') | |
alert('做一堆其他的事情......') | |
console.timeEnd('answer time') |
04 给打印编组
可以使用嵌套组来把一组关联的打印合并。用 console.group()
可以创建新的嵌套块,用 console.groupCollapsed()
创建默认折叠的块。嵌套组需要通过 console.groupEnd()
闭合。
示例:
// 为了方便观察,我用缩进表示了层级 | |
console.log('A1') | |
console.group() | |
console.log('B1') | |
console.info('B2') | |
console.group() | |
console.warn('C1') | |
console.warn('C2') | |
console.groupCollapsed() | |
console.error('D1') | |
console.error('D2') | |
console.groupEnd() | |
console.warn('C3') | |
console.groupEnd() | |
console.debug('B3') | |
console.info('B4') | |
console.groupEnd() | |
console.debug('A2') |
05 堆栈跟踪
通过 console.trace
可以追踪函数的调用路径。这么说起来很抽象,简单来讲就是,把 console.trace()
放在一个方法中,一旦 console.trace()
被调用了,那么就会输出从一开始到 console.trace()
的所有方法的执行路径。
通过例子或许能很好的理解。
5.1 示例一:
function outer() { | |
function inner() { | |
console.trace() | |
} | |
inner() | |
} | |
outer() |
由于是堆栈信息,所以得倒着看,执行到 console.trace()
的时候,是调用了 outer
和 inner
这两个方法。
5.2 示例二:
function add(a, b) { | |
console.trace() | |
return a + b | |
} | |
function add1(a, b) { | |
return add(a, b) | |
} | |
function add2(a, b) { | |
return add1(a, b) | |
} | |
function add3(a, b) { | |
return add2(a, b) | |
} | |
const result = add3(1, 1) |
同理,执行到 console.trace()
的时候,是调用了 add1
、 add2
、add3
和 add
这四个方法。
console.trace()
有时候对于接手别人写的复杂模块的时候,还是挺有用的。
06 打印花里胡哨
6.1 样式占位符
很多编程语言的打印方法,都有占位符这样的东西。比如 C 语言的 printf("%d ", 10)
,其中的 %d
表示十进制整型数据,这里输出 10。
JavaScript 也有占位符,不过用的比较少。但是通过占位符可以实现一些花里胡哨的信息。
JavaScript 支持的占位符:
%s
:字符串%d
:整数%i
:整数%f
:浮点数%o
:DOM 对象%O
:JavaScript 对象%c
:CSS 样式
其中的 %c
是 JavaScript 特有的,可以标记从该 %c
开始后续行的样式。
例如:
console.log(`欢迎加入我们的%c大家庭`, `font-size: 30px; font-weight: bold; color: #ef475d`)
也可以标记多个样式,只需要 %c
和样式对应上。例如:
console.log( | |
`欢迎加入我们的%c大家庭 | |
%c啦啦啦 | |
`, | |
`font-size: 30px; font-weight: bold; color: #ef475d`, | |
`font-size: 24px; font-weight: bold; color: cornflowerblue` | |
) |
学会了 %c
的用法,就能玩出很多花样。
比如这样:
console.log(`%c | |
%c FBI WARNING %c | |
%c Federal Law provides severe civil and criminal penalties for | |
the unauthorized reproduction,distribution, or exhibition of | |
copyrighted motion pictures (Title 17, United States Code, | |
Sections 501 and 508). The Federal Bureau of Investigation | |
investigates allegations of criminal copyright infringement | |
(Title 17, United States Code, Section 506). | |
`, | |
'background: #000; font-size: 18px; font-family: monospace', | |
'background: #f33; font-size: 18px; font-family: monospace; color: #eee; text-shadow:0 0 1px #fff', | |
'background: #000; font-size: 18px; font-family: monospace', | |
'background: #000; font-size: 18px; font-family: monospace; color: #ddd; text-shadow:0 0 2px #fff' | |
) |
6.2 ASCII Art
ASCII Art,是指用一串或一片字符,去构成图案。它是早期互联网上,带宽小、流量少、部分终端不能显示图片的背景下,产出一种表达形式。文字表情(颜文字)其实就是 ASCII Art 的一种。
听起来比较抽象,直接上才艺:
- 文字表情(颜文字)
╮( ̄▽  ̄)╭ | |
__ ___ _____ | |
\ \ / (_) / ____| | |
\ V / _ __ _ ___ | | _ _ ___ | |
> < | |/ _` |/ _ | | | | | |/ _ \ | |
/ . | | (_| | (_) | |___| |_| | (_) | | |
/_/ __|__,_|___/ _______,_|___/ | |
/** | |
* | |
* _ooOoo_ | |
* o8888888o | |
* 88" . "88 | |
* (| -_- |) | |
* O\ = /O | |
* ____/`---'____ | |
* .' \| |// `. | |
* / \||| : |||// \ | |
* / _||||| -:- |||||- \ | |
* | | \\ - /// | | | |
* | _| ''---/'' | | | |
* \ .-__ `-` ___/-. / | |
* ___`. .' /--.--\ `. . __ | |
* ."" '< `.____<|>_/___.' >'"". | |
* | | : `- `.;`\ _ /`;.`/ - ` : | | | |
* \ \ `-. _ __\ /__ _/ .-` / / | |
* ======`-.____`-.________/___.-`____.-'====== | |
* `=---=' | |
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
* 佛祖保佑 永无BUG | |
* | |
*/ | |
ASCII Art 这个概念或许你很陌生,但是以上的例子,你应该很熟悉。