JavaScript中的console
前言
之前调试JS代码用的一直是console.log(),偶然间了解到console 对象拥有多种方法可以更好的呈现信息。调试代码时可根据不同情况选择不同的console,从而给代码调试带来方便。根据常用程度,列出以下几种 console 对象的方法:
- console.log()、console.debug()、console.info()、console.warn() 与 console.error()
- console.table()
- console.time() 与 console.timeEnd()
- console.assert()
- console.count()
- console.group、console.groupEnd() 与 console.groupCollapsed()
- console.dir()
以下示例的运行环境是VSCode中的Nodejs和谷歌浏览器。
console对象
console.log()
console.log
是最常用的打印信息方法,它可以接受多个参数,逗号分隔。它会自动在每次输出的结尾,添加换行符。没有返回值回会返回undefined
。
如果第一个参数是格式字符串(使用了格式占位符),console.log
方法将依次用后面的参数替换占位符,然后再进行输出。
console.log('hello %s', 'world');
// hello world
console.log("%d年%d月%d日", 2022, 05, 23)
// 2022年5月23日
占位符格式如下表:
模式 | 类型 |
---|---|
%s | 字符串 |
%d,%i | 整数 |
%f | 浮点数 |
%o | 对象超链接 |
%c | CSS格式化样式 |
console.log()
方法和console.debug()
、console.info()
、console.warn()
与 console.error()
几乎完全一样,唯一不同的是现实中浏览器的表现形式了。(在nodejs运行环境中表现形式相同)
注意:IE不支持debug()方法
console.table()
console.table()
方法可以将传入的对象或数组这些复合数据以表格形式输出。
const people = {
"person1": {"name": "zhangsan", "age": "20"},
"person2": {"name": "lisi", "age": "21"},
"person3": {"name": "wangwu", "age": "22"}
};
console.log(people);
console.table(people);
所以从上面两种输出我们可以看出,当输出类似于这种两层嵌套的对象时,我们可以选择 console.table()
以表格的形式输出。当然,嵌套三层及以上的也会以表格形式输出,但限于表格只能显示二维信息的特点,其会在嵌套三层或以上的地方会显示 “Object” 字符串。
console.time() 与 console.timeEnd()
console.time()
,console.timeEnd()
方法计算一个操作的执行的时间console.time()
是开始,console.timeEnd()
是结束。可以传一个参数,参数为计时器的名称。
console.time('计时器');
for (var i = 0; i < 100; i++) {
for (var j = 0; j < 100; j++) {}
}
console.timeEnd('计时器');
// 计时器: 0.196ms
console.time('wait');
setTimeout(()=>{
console.timeEnd('wait');
},1000);
// wait: 1008.538ms
console.assert()
如果第一个参数的值为假值或省略,则 console.assert()
写入一条消息,将会在控制台上抛出一个异常并将第二个参数作为异常描述输出。 它只写入一条消息,不会影响执行。 输出始终以 “Assertion failed” 开头。
如果第一个参数的值为真值,则什么也不会发生。
console.assert(true, 'does nothing');
console.assert(false, 'Whoops %s work', 'didn\'t');
// Assertion failed: Whoops didn't work
console.assert();
// Assertion failed
也可以直接进行判断,类似于单元测试中的断言,当表达式为 false 时,输出错误信息。示例如下:
const arr = [1, 2, 3];
console.assert(arr.length === 4);
// Assertion failed
注意:Node.js 中的 console.assert() 方法与在浏览器中的 console.assert() 方法的实现是不一样的。
具体地说,在浏览器中,用非真的断言调用console.assert()
会导致 message 被打印到控制台但不会中断后续代码的执行。 而在 Node.js 中,非真的断言会导致抛出AssertionError
。
可以通过扩展 Node.js 的 console 并重写console.assert()
方法来实现与浏览器中类似的功能。
例子,创建一个简单的模块,并扩展与重写了 Node.js 中 console 的默认行为。
'use strict';
// 用一个新的不带补丁的 assert 实现来创建一个简单的 console 扩展。
const myConsole = Object.create(console, {
assert: {
value: function assert(assertion, message, ...args) {
try {
console.assert(assertion, message, ...args);
} catch (err) {
console.error(err.stack);
}
},
configurable: true,
enumerable: true,
writable: true,
},
});
module.exports = myConsole;
然后可以用来直接替换内置的 console:
const console = require('./myConsole');
console.assert(false, '会打印这个消息,但不会抛出错误');
console.log('这个也会打印');
console.count()与console.countReset()
console.count()
方法用于计数,输出它被调用了多少次。
for (var i = 0; i < 5; i++) {
console.count('count');
}
// count: 1
// count: 2
// count: 3
// count: 4
// count: 5
console.count()
参数默认值为'default'
:
console.count()
// default: 1
console.count('default')
// default: 2
console.count()
// default: 3
console.countReset()
用于重置特定于console.count()
的内部计数器。
console.count('abc');
// abc: 1
console.countReset('abc');
console.count('abc');
// abc: 1
console.group()、 console.groupEnd() 与 console.groupCollapsed()
一般的console.log()
方法的输出没有层级关系,在需要一些显示层级关系的输出中显得苍白无力,使用console.group()
可以达到我们的目的。示例代码如下:
console.group("1");
console.log("1-1");
console.log("1-2");
console.log("1-3");
console.groupEnd();
console.group("2");
console.log("2-1");
console.log("2-2");
console.log("2-3");
console.groupEnd();
// 1
// 1-1
// 1-2
// 1-3
// 2
// 2-1
// 2-2
// 2-3
console.group()
和console.groupCollapsed()
这两个方法用法都是一样的。唯一区别就是在浏览器中console.group()
是默认展开的,而console.groupCollapsed()
默认是收起的,在node.js中显示无差别。
console.group('第一层');
console.groupCollapsed('第二层');
console.log('error');
console.error('error');
console.warn('error');
console.groupEnd();
console.groupEnd();
浏览器显示结果:
nodejs显示结果:
console.dir()
console.dir()
方法用来对一个对象进行检查,并以易于阅读和打印的格式显示。
var obj1 = {
name: 'zhangsan',
age: '18',
type: {
"A" : "a",
"B" : "b",
"C" : "c"
}
};
console.dir(obj1);
var arr = [1,2,3]
console.dir(arr)
var s = 'abcde'
console.dir(s)
var n = 123
console.dir(n)
在谷歌浏览器运行结果为:
点击展开显示为:
换成console.log()
方法则为:
显示内容有一定的差别。
在nodejs环境中显示内容没有差别:
但是在对象嵌套层级过多的情况下,在第2级之后的嵌套对象会被扁平化,如下:
var obj = {
name: 'joe',
age: 35,
person1: {
name: 'Tony',
age: 50,
person2: {
name: 'Albert',
age: 21,
person3: {
name: 'Peter',
age: 23,
},
},
},
};
console.dir(obj)
// {
// name: 'joe',
// age: 35,
// person1: {
// name: 'Tony',
// age: 50,
// person2: { name: 'Albert', age: 21, person3: [Object] }
// }
// }
console.log(obj)
// {
// name: 'joe',
// age: 35,
// person1: {
// name: 'Tony',
// age: 50,
// person2: { name: 'Albert', age: 21, person3: [Object] }
// }
// }
可以通过以下方式解决:
// 'depth'告诉util.inspect()格式化对象时递归的次数,默认为2
console.dir(obj, {
depth: 10
});
// ...或者传递' null '来无限递归
console.dir(obj, {
depth: null
});
// {
// name: 'joe',
// age: 35,
// person1: {
// name: 'Tony',
// age: 50,
// person2: { name: 'Albert', age: 21, person3: { name: 'Peter', age: 23 } }
// }
// }
此外在 Chrome 中打印 DOM 元素时,两个方法输出的结果也大不一样。console.log()
会将 DOM 元素以 HTML 的形式输出,而console.dir()
则会以 JSON 对象的形式输出。
在Node.js中,同样的情况也会发生。
当我们将一些东西记录到控制台时,我们没有这样的特权,因为如果手动运行Node.js程序,它会将对象输出到shell,或者输出到日志文件。你得到对象的字符串表示。
现在,一切都很好,直到一定程度的嵌套。在两层嵌套之后,Node.js放弃并打印[Object]
作为一个占位符:
const obj = {
name: 'joe',
age: 35,
person1: {
name: 'Tony',
age: 50,
person2: {
name: 'Albert',
age: 21,
person3: {
name: 'Peter',
age: 23,
},
},
},
};
console.log(obj);
拓展
如何在Node.js中log一个对象
当你在浏览器中运行的JavaScript程序中输入console .log()
时,会在浏览器控制台中创建一个不错的条目,一旦你点击箭头,日志就展开了,你可以清楚地看到对象属性。
在Node.js中,同样的情况也会发生。
当我们将一些东西记录到控制台时,我们没有这样的特权,因为如果手动运行Node.js程序,它会将对象输出到shell,或者输出到日志文件。你得到对象的字符串表示。
现在,一切都很好,直到一定程度的嵌套。在两层嵌套之后,Node.js放弃并打印[Object]
作为一个占位符。
如何打印整个物体?如何做到这一点同时保留漂亮的印刷?
- JSON.stringify
console.log(JSON.stringify(obj, null, 2));
- console.dir
console.dir(obj, {
depth: null,
});
console异步还是同步?
原问题:
https://stackoverflow.com/questions/23392111/console-log-async-or-sync
在Chrome和nodejs中分别执行以下代码
var obj = {};
console.log(obj);
obj.foo = 'bar';
nodejs结果:
{}
Chrome结果:
发生这种现象的原因是:
控制台将需要将记录的值存储在某处,并将其显示在屏幕上。渲染将会以异步方式发生(被限制到速率限制更新),以及将来与控制台中记录的对象的交互(如扩展对象属性)的交互。
因此,控制台可能会克隆(序列化)您记录的可变对象,也可能存储对它们的引用。第一个对深层物体不能很好地工作。此外,至少在控制台中的初始呈现可能会显示对象的“当前”状态,即当您记录的示例中的对象的状态Object {}。但是,当您扩展对象以进一步检查其属性时,控制台可能只存储对对象及其属性的引用,并且现在显示它们将显示其当前(已突变)状态。
简单来讲就是:WebKit的console.log
并没有立即拍摄对象快照,相反,它只存储了一个指向对象的引用,然后在代码返回事件队列时才去拍摄快照。Node的console.log
是另一回事,它是严格同步的,因此同样的代码输出的却为{}
参考:
console对象–详解
JavaScript 中 console 的用法
console 控制台 | Node.js API文档
控制台(console)| Node.js 中文文档 | Node.js 中文网
How to log an object in Node.js
console异步还是同步