console.log 真的可信吗?

6,907 阅读3分钟

前言

相信大家都会平时在调试代码时,都会用上 console.logdebugger或者调试工具。但是一般顺手的情况下,我们大多数都会使用console.log,但是console.log真的可信吗?

结论:console.log在打印引用类型的数据,可能会不准确。在复杂的断点调试时,尽可能使用debugger或者调试工具

console.log 打印异常

var a = {
  index: 1,
}
console.log(a)
a.index++
console.log(a)

以上代码分别运行在不同的三种情况下,你会发现比较有意思的地方:

  1. node.js 平台

  1. web 端控制台未打开的情况(注:这里指运行代码后再打开控制台)

  1. web 端控制台打开的情况(注:这里指打开控制台进行刷新)

注:以上 web 端经过现代浏览器测试发现:chrome、edge、firefox 表现形式一致,与上述类似。safari 在第三种情况下无法进行展开对象。

异常分析

web 端为何表现和 node.js 不同

我们都知道引用类型,每次使用对象时,都只是使用了对象在堆中的引用。在 node.js 平台的情况是我们预期的情况,而在 web 端为何会出现如此情况呢?

在 《你不知道的javascript中卷》 中提及过:console.* 方法族并不是JavaScript 正式的一部分,而是由宿主环境添加到JavaScript 中的。因此,不同的浏览器和JavaScript 环境可以按照自己的意愿来实现。

而在大多数浏览器中,console.log 并不会把传入的内容立即输出,而是交给浏览器进行异步进行处理,提高性能。

在这里本人简单理解为:node.js 平台为同步打印,浏览器平台为异步打印。

web 端控制台是否打开为何不同

未打开控制台

console.log在大多数浏览器中是在控制台打开后才起作用,也就是说,当你打开控制台时,才会进行打印。

在上述代码中,传进console.log中的参是一个地址,当代码执行完毕后,打开控制台,开始打印,那么它打印出的实际上是已经做完全部处理后的对象。这就相当于这样的执行顺序:

var a = {
  index: 1,
}
a.index++
console.log(a)
console.log(a)

打开控制台

打开控制台再运行代码(即打开控制台后进行刷新),那么console.log是直接起作用的。浏览器有个快照技术,所以我们可以看见我们在控制台看见的即为正确结果。但是我们地址对应的那个对象还是最终的样子,所以展开后不同。

解决方案

深拷贝(不推荐)

console.log(JSON.parse(JSON.stringify(a)));

对当前的对象进行一次深拷贝,然后再次输出。

深拷贝之后,就不再指向同一处的堆。

debugger 或者 调试工具

利用 debugger 或者 调试工具 能让我们避免错误,我们应该在平时工作中经常使用。