console的高级用法

前言

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

于是就萌生了学一波 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
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([["Anzhiyu", "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://anheyu.com 56 %c 789", "font-size:20px;color:#3b70fc;", "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/anheyu.com.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
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 = [
`欢迎来到Anzhiyu\`Blog!`,
`生活明朗, 万物可爱`,
`

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

`,
"Anzhiyu`Blog 已上线",
dnum,
"天",
"©2021 By Anzhiyu",
];

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:#3b70fc",
"",
"color:#3b70fc",
"color:#3b70fc",
"",
"color:#3b70fc",
""
)
);
}

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 Anzhiyu %c 你正在访问 Anzhiyu 的博客.",
"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 () {};

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

啦啦啦~

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