前言

前几天在看青柠起始页的时候偶然间看到它的控制台居然可以这样 👊

于是就萌生了学一波 console 方法的念头,今天正好有时间就来把这几天的学习成果记录一下 😶

console 的基本用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
console.log('最常见用法\n换行')

console.error('输出错误信息 会以红色显示')

console.warn('打印警告信息 会以黄色显示')

console.info('打印一般信息')

// console.clear();//清空上面的console显示

//进阶用法
//console.assert(bool,”info”) 如果bool为false 打印出info 否则不打印
console.assert(false, '判断为false才显示的信息')
//传入的对象或数组以表格方式显示
console.table([['Violet', 'Chen'], ['好']])
//打印 调用链 fn2()调用fn1(),fn1()调用fn()
function fn() {
console.trace()
}
function fn1() {
fn()
}
function fn2() {
fn1()
}
fn2()

//格式化输出
/*
console.log支持的格式标志有:
%s 占位符
%d 或 %i 整数
%f 浮点数
%o%O object对象
%c css样式
*/

console.log('%d + %d = %d', 1, 2, 3)
//%o%O打印dom节点时就不一样
console.log('%o', document.body)
console.log('%O', document.body)
// %c 后面的内容,增加css样式
//附:console.log输出的超链接会被自动识别并加上灰色字体颜色和下划线的样式,而这个无法用%c覆盖
console.log('123 %c 456', 'font-size:36px;color:red;')
console.log(
'123 %c 4 https://qwq3.top 56 %c 789',
'font-size:20px;color:#49b1f5;',
'font-size:12px;color:#000'
)
//利用css样式加载图片
//没法直接设置width和height样式,line-height图片高度,再调padding
console.log(
'%c ',
'background-image:url("https://cdn.jsdelivr.net/gh/waterchen520/cdn2@latest/qwq3.top.jpg");background-size:120% 120%;background-repeat:no-repeat;background-position:center center;line-height:60px;padding:30px 120px;'
)
//高级用法
//计时,单位毫秒
console.time()
for (var i = 0; i < 100000; i++) {
var j = i * i
}
console.timeEnd()
//统计代码或函数被调用了多少次
var fn_ = function () {
console.count('hello world')
}
for (var i = 0; i < 5; i++) {
fn_()
}
//查看内存使用情况,是属性,不带括号
//console.memory;
//在浏览器开发者工具中使用
//分组输出,可嵌套
console.group('分组1')
console.log('语文')
console.log('数学')
console.group('其他科目')
console.log('化学')
console.log('地理')
console.log('历史')
console.groupEnd('其他科目')

展开上面代码运行可以得到

注意以上某些方法某些浏览器IE:没错就是我不支持

console 详解

让我们来看看谷歌浏览器提供的 console 方法的 API https://developer.chrome.com/docs/devtools/console/

我们来重写 console,发现它里面有很多方法

console.assert(expression, object)

在被评估的表达式为 false 时向控制台写入一个错误。

1
2
3
4
function greaterThan(a, b) {
console.assert(a > b, { message: 'a is not greater than b', a: a, b: b })
}
greaterThan(5, 6)

console.clear()

清除控制台。

1
console.clear();1

如果已启用 Preserve log 复选框,console.clear() 将停用。 不过,在控制台处于聚焦状态时,按 clear console 按钮或者输入 Ctrl+L 快捷键仍然有效。

console.count(label)

写入在同一行使用相同标签调用 count() 的次数。

1
2
3
function login(name) {
console.count(name + ' logged in');
}

console.debug(object [, object, …])

console.log() 作用相同。

console.dir(object)

输出以 JavaScript 形式表示的指定对象。如果正在记录的对象是 HTML 元素,将输出其以 DOM 形式表示的属性,如下所示:

1
console.dir(document.body);

比 console.log 更加详细

console.dirxml(object)

如果可以,输出 object 子级元素的 XML 表示形式,否则输出其 JavaScript 表示形式。 在 HTML 和 XML 元素上调用 console.dirxml() 等同于调用 console.log()

1
console.dirxml(document)

console.error(object [, object, …])

输出一条类似于 console.log() 的消息,将消息设置成错误样式,并在调用此方法的地方包含一个堆叠追踪。

1
console.error('error: name is undefined');

console.group(object[, object, …])

启动一个带有可选标题的新日志组。以可视化方式将在 console.group() 后、console.groupEnd() 前发生的所有控制台输出组合在一起。

1
2
3
4
5
6
7
8
9
function name(obj) {
console.group('name')
console.log('first: ', obj.first)
console.log('middle: ', obj.middle)
console.log('last: ', obj.last)
console.groupEnd()
}

name({ first: 'Wile', middle: 'E', last: 'Coyote' })

您还可以嵌套组:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function name(obj) {
console.group('name')
console.log('first: ', obj.first)
console.log('middle: ', obj.middle)
console.log('last: ', obj.last)
console.groupEnd()
}

function doStuff() {
console.group('doStuff()')
name({ first: 'Wile', middle: 'E', last: 'coyote' })
console.groupEnd()
}

doStuff()

console.groupCollapsed(object[, object, …])

创建一个初始处于折叠状态而不是打开状态的新日志组。

1
2
3
console.groupCollapsed('status')
console.log("peekaboo, you can't see me")
console.groupEnd()

console.groupEnd()

关闭日志组。相关示例请参阅 console.group

console.info(object [, object, …])

输出一条类似 console.log() 的消息,但同时在输出旁显示一个图标(带白色“i”的蓝色圆圈)。

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

在控制台中显示一条消息。将一个或多个对象传递到此方法。每个对象都会进行评估并级联到一个由空格分隔的字符串中。

1
console.log('Hello, Logs!')

格式说明符

您传递的第一个对象可以包含一个或多个格式说明符。格式说明符由百分号 (%) 与紧跟其后面的一个字母组成,字母指示要应用的格式。

console.profile([label])

启动一个带有可选标签的 JavaScript CPU 配置文件。要完成配置文件,请调用 console.profileEnd()。 每一个配置文件都会添加到 Profiles 面板中。

1
2
3
4
5
function processPixels() {
console.profile('processPixels()')
// later, after processing pixels
console.profileEnd()
}

console.profileEnd()

停止当前的 JavaScript CPU 分析会话(如果正在进行此会话),并将报告输出到 Profiles 面板中。

console.time(label)

启动一个具有关联标签的新计时器。使用相同标签调用 console.timeEnd() 时,定时器将停止,经过的时间将显示在控制台中。计时器值精确到亚毫秒。传递到 time()timeEnd() 的字符串必须匹配,否则计时器不会结束。

1
2
3
4
5
6
console.time('Array initialize')
var array = new Array(1000000)
for (var i = array.length - 1; i >= 0; i--) {
array[i] = new Object()
}
console.timeEnd('Array initialize')

console.timeEnd(label)

停止当前的计时器(如果正在运行一个计时器),并将计时器标签和经过的时间输出到控制台。

console.timeStamp([label])

在录制会话期间向 Timeline 添加一个事件。

1
console.timeStamp('check out this custom timestamp thanks to console.timeStamp()!')

console.trace(object)

从调用此方法的位置输出一个堆叠追踪。

1
console.trace()

console.warn(object [, object, …])

输出一条类似 console.log() 的消息,但同时在记录的消息旁显示一个黄色警告图标。

1
console.warn('user limit reached!')

重写简单的 console 方法

我们常用的有 console.log、console.info、console.group、console.warn、console.error、console.profile、console.time,现在我们来试着重写 console.log、console.info、console.group、console.warn、console.error 这几个常用的,其他的类似但比较复杂。

第一步,搭一个结构,覆盖浏览器(chrome\ie)提供的 console 功能,这样直接引用此 JS 文件即可保证浏览器(主要是 IE)中不出错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var console = {
assert: function () {},
clear: function () {},
count: function () {},
debug: function () {},
dir: function () {},
dirxml: function () {},
error: function () {},
exception: function () {},
group: function (name) {},
groupCollapsed: function () {},
groupEnd: function () {},
info: function () {},
log: function () {},
memoryProfile: function () {},
memoryProfileEnd: function () {},
profile: function () {},
profileEnd: function () {},
table: function () {},
time: function () {},
timeEnd: function () {},
timeStamp: function () {},
trace: function () {},
warn: function () {},
}

第二步,实现 console.log 方法。在所实现的几个方法中这个是最复杂的。

从 chrome 的 API 中我们可以看到,console.log 不仅仅可以输出信息,还提供了类似 string.Format 的功能,原文地址:https://developer.chrome.com/docs/devtools/console/api/

Here is the complete set of patterns that you may use for string substitution:

PatternType
%sString
%d, %iInteger (numeric formatting is not yet supported)
%fFloating point number (numeric formatting is not yet supported)
%oObject hyperlink
%cStyle formatting

其中的%c 比较特殊,是给输出添加样式的,比如我们在 Chrome 中这样写:

1
console.log('%cTest output', 'color:white; background-color:blue')

运行后的结果是这样的:

这里%c 也可以跟 %s、%d 等混用。

所以,在代码中我直接用 replace 进行替换,由于 JS 中的 replace 默认只替换第一个匹配项,这里刚好,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
var args = Array.prototype.slice.call(arguments)
if (args.length > 1) {
var i = 1,
hasstyle = false
if (args[0].indexOf('%c') == 0) {
args[0] = args[0].replace(/%c/, '')
i = 2
hasstyle = true
}
for (; i < args.length; i++) {
if (/%s|%d|%i|%o/.test(args[0])) {
args[0] = args[0].replace(/%s|%d|%i|%o/, args[i])
} else {
break
}
}
if (i < args.length) {
args[0] = args[0] + ' ' + args.slice(i).join(' ')
}
if (hasstyle) {
consoleHelper.showlog(args[0], args[1])
} else {
consoleHelper.showlog(args[0])
}
} else if (args.length == 1) {
if (arguments[0] instanceof Array) {
consoleHelper.showlog('[' + args[0] + ']')
} else if (arguments[0] instanceof Function) {
consoleHelper.showlog(args[0], null, 'console_log_function')
} else {
consoleHelper.showlog(args[0])
}
} else {
consoleHelper.showlog('')
}

由于 console.log 可以接受多个参数,且个数不确定,所以这里直接没有写形参。对于%c 虽然 Chrome 中写在中间也是有效的,这里为了简单直接只对写在开头的有效。代码中先把参数转换为数组,然后对数组进行分情况处理。

当参数个数大于 1 时,对后面的参数用 replace 进行替换,然后把剩下的参数连接(join)起来进行输出。

当参数个数为 1 时,还要分两种情况,一是数组,二是方法。对于数组,按 Chrome 中的格式,在两端加中括号,对于函数,把字的颜色变为绿色

当参数个数为 0 时,直接输出空字符串

后面的 consoleHelper.showlog 是为了输出方便另外写的一个方法,在这个方法中把各种调试信息的结果显示在页面上的一个 div(如果存在)中。

其他几个方法的思路跟这个差不多,只是样式不同,功能比这个简单,直接把参数连接起来输出即可。

整个 console 类代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
var console = {
assert: function () {},
clear: function () {},
count: function () {},
debug: function () {},
dir: function () {},
dirxml: function () {},
error: function () {
var args = Array.prototype.slice.call(arguments)
consoleHelper.showerror(args.join(' '))
},
exception: function () {},
group: function (name) {
consoleHelper.showgroup(name)
},
groupCollapsed: function () {},
groupEnd: function () {},
info: function () {
var args = Array.prototype.slice.call(arguments)
if (args.length == 1) {
if (arguments[0] instanceof Array) {
consoleHelper.showinfo('[' + args[0] + ']')
} else if (arguments[0] instanceof Function) {
consoleHelper.showinfo(args[0], 'console_log_function')
} else {
consoleHelper.showinfo(args[0])
}
} else {
consoleHelper.showinfo(args.join(' '))
}
},
log: function () {
var args = Array.prototype.slice.call(arguments)
if (args.length > 1) {
var i = 1,
hasstyle = false
if (args[0].indexOf('%c') == 0) {
args[0] = args[0].replace(/%c/, '')
i = 2
hasstyle = true
}
for (; i < args.length; i++) {
if (/%s|%d|%i|%o/.test(args[0])) {
args[0] = args[0].replace(/%s|%d|%i|%o/, args[i])
} else {
break
}
}
if (i < args.length) {
args[0] = args[0] + ' ' + args.slice(i).join(' ')
}
if (hasstyle) {
consoleHelper.showlog(args[0], args[1])
} else {
consoleHelper.showlog(args[0])
}
} else if (args.length == 1) {
if (arguments[0] instanceof Array) {
consoleHelper.showlog('[' + args[0] + ']')
} else if (arguments[0] instanceof Function) {
consoleHelper.showlog(args[0], null, 'console_log_function')
} else {
consoleHelper.showlog(args[0])
}
} else {
consoleHelper.showlog('')
}
},
memoryProfile: function () {},
memoryProfileEnd: function () {},
profile: function () {},
profileEnd: function () {},
table: function () {},
time: function () {},
timeEnd: function () {},
timeStamp: function () {},
trace: function () {},
warn: function () {
var args = Array.prototype.slice.call(arguments)
if (args.length == 1) {
if (arguments[0] instanceof Array) {
consoleHelper.showwarn('[' + args[0] + ']')
} else if (arguments[0] instanceof Function) {
consoleHelper.showwarn(args[0], 'console_log_function')
} else {
consoleHelper.showwarn(args[0])
}
} else {
consoleHelper.showwarn(args.join(' '))
}
},
}

consoleHelper 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
var consoleHelper = {
showlog: function (val, style, cla) {
if (cla) {
cla = 'console_log ' + cla
} else {
cla = 'console_log'
}
this.show(val, style, cla)
},
showinfo: function (val, cla) {
if (cla) {
cla = 'console_info ' + cla
} else {
cla = 'console_info'
}
this.show(val, null, cla)
},
showwarn: function (val, cla) {
if (cla) {
cla = 'console_warn ' + cla
} else {
cla = 'console_warn'
}
this.show(val, null, cla)
},
showerror: function (val) {
this.show(val, null, 'console_error')
},
showgroup: function (val) {
if (!val) {
val = ''
}
this.show(val + ':', null, 'console_group')
},
show: function (val, style, cla) {
if (document.getElementById('showconsole')) {
var div = document.createElement('div')
if (div.setAttribute) {
if (style) {
div.setAttribute('style', style)
}
} else {
if (style) {
div = document.createElement('<div style=' + style + '>')
}
}
if (cla) {
div.className = cla
}
var oText = document.createTextNode(val)
div.appendChild(oText)
document.getElementById('showconsole').appendChild(div)
}
},
}

注:如果想在页面中看到调试信息,直接在页面上添加一个id 为 showconsole 的隐藏的div即可。

样式(尽量跟 Chrome 保持一致):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
.console_log {
border: 1px solid #ccc;
color: #333;
padding: 0px 5px;
min-height: 24px;
line-height: 24px;
margin-bottom: -1px;
}
.console_info {
border: 1px solid #ccc;
color: #333;
padding: 0px 5px;
min-height: 24px;
line-height: 24px;
margin-bottom: -1px;
background: url('这里是info方法的小图标') no-repeat scroll 0 1px #ebf5ff;
padding-left: 30px;
}
.console_warn {
border: 1px solid #ccc;
color: #333;
padding: 0px 5px;
min-height: 24px;
line-height: 24px;
margin-bottom: -1px;
background: url('这里是warn方法的小图标') no-repeat scroll 0 1px #ffffc8;
padding-left: 30px;
}
.console_error {
border: 1px solid #ccc;
color: #ff0000;
padding: 0px 5px;
min-height: 24px;
line-height: 24px;
margin-bottom: -1px;
background: url('这里是error方法的小图标') no-repeat scroll 0 1px #ffebeb;
padding-left: 30px;
}
.console_group {
margin-top: 20px;
font-size: 16px;
font-weight: bolder;
}
.console_log_function {
color: green;
}

这里为了演示方便,三个小图标直接预留了位置,大家用时可以换成图片地址。

代码实现案例

如果只需要一个简单的,类似我博客里的这种,你只需要写一个 js

下面是本博客控制台的 js 源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
var now1 = new Date()

function createtime1() {
var grt = new Date('04/01/2021 00:00:00') //此处修改你的建站时间或者网站上线时间
now1.setTime(now1.getTime() + 250)
var days = (now1 - grt) / 1000 / 60 / 60 / 24
var dnum = Math.floor(days)

var ascll = [
`欢迎来到Violet\`Blog!`,
`生活明朗, 万物可爱`,
`

██╗ ██╗██╗ ██████╗ ██╗ ███████╗████████╗
██║ ██║██║██╔═══██╗██║ ██╔════╝╚══██╔══╝
██║ ██║██║██║ ██║██║ █████╗ ██║
╚██╗ ██╔╝██║██║ ██║██║ ██╔══╝ ██║
╚████╔╝ ██║╚██████╔╝███████╗███████╗ ██║
╚═══╝ ╚═╝ ╚═════╝ ╚══════╝╚══════╝ ╚═╝

`,
'Violet`Blog 已上线',
dnum,
'天',
'©2021 By Violet',
]

setTimeout(
console.log.bind(
console,
`\n%c${ascll[0]} %c ${ascll[1]} %c ${ascll[2]} %c${ascll[3]}%c ${ascll[4]}%c ${ascll[5]}\n\n%c ${ascll[6]}\n`,
'color:#49b1f5',
'',
'color:#49b1f5',
'color:#49b1f5',
'',
'color:#49b1f5',
''
)
)
}

createtime1()

function createtime2() {
var ascll2 = [`NCC2-036`, `调用前置摄像头拍照成功,识别为【小笨蛋】.`, `Photo captured: `, ` `]

setTimeout(
console.log.bind(
console,
`%c ${ascll2[0]} %c ${ascll2[1]} %c \n${ascll2[2]} %c\n${ascll2[3]}\n`,
'color:white; background-color:#4fd953',
'',
'',
'background:url("https://unpkg.zhimg.com/anzhiyu-assets@latest/image/common/tinggge.gif") no-repeat;font-size:450%'
)
)

setTimeout(
console.log.bind(
console,
'%c WELCOME %c 你好,小笨蛋.',
'color:white; background-color:#4f90d9',
''
)
)

setTimeout(
console.warn.bind(
console,
'%c ⚡ Powered by Violet %c 你正在访问 Violet 的博客.',
'color:white; background-color:#f0ad4e',
''
)
)

setTimeout(
console.log.bind(
console,
'%c W23-12 %c 你已打开控制台.',
'color:white; background-color:#4f90d9',
''
)
)
setTimeout(
console.warn.bind(
console,
'%c S013-782 %c 你现在正处于监控中.',
'color:white; background-color:#d9534f',
''
)
)
}
createtime2()

console.log = function () {}

写下这篇博客的时候 📌,已经忘记参考地址是哪里了,算是一个汇总吧,参考地址百度

啦啦啦~

我一直想从你的窗子里看月亮。💡~