关于Console.log
date
Oct 13, 2020
slug
console
status
Published
tags
JavaScript
summary
一个奇怪的特性
type
Post
最近在帮同学调试问题的时候,
console.log()
的输出真是震惊我,居然出现了类似异步输出的表现,直接把我带偏了,于是我查阅了资料,并将其记录下来。问题本身:
function Fn(){
this.a =1;
this.__proto__.b =2
}
let fn2 = new Fn();
let fn3 = new Fn();
console.log(fn2.__proto__.b)
console.log(fn2)
console.log(fn3.__proto__.b)
console.log(fn3)
fn3.__proto__.b =3;
输出:

可以看到fn2和fn3的__proto__.b和期望输出的值是一样的,而当把fn2和fn3展开后:

他们的值都从2变成了3
为什么会出现这样的原因呢
JS中,对象和数组都是引用类型,每次使用他们时,都只是使用了对象在堆中的引用。当它输出的时候,确实就是那个时候的值,但是后面有其他操作改变了他们的值,由于他们指向同一个,展开来看的时候就变成了最新的值。
《JavaScript异步编程》中这样解释:
Webkit的
console.log()
并没有立即拍摄对象快照,相反,它只存储了一个指向对象的引用,然后在代码返回事件队列时才去拍摄快照。而Node中的
console.log()
又是另一回事了,它是严格同步的,因此输出的代码都是正确的。
书中指出,JavaScript 环境提供的异步函数一般分为两大类:I/O函数和计时函数。
console.log
就是一个I/O函数。对于引用类型,console.log
会先储存一个引用,因此在打印引用类型时结果不一定准确。《你不知道的JavaScript中卷》第二部分异步和性能中也有提及:
在某些情况下,某些浏览器的
console.log()
并不会把传入的内容立即输出,出现这种情况的主要原因是,在许多程序中,I/O是非常低速的阻塞部分。所以(从页面/UI的角度说)浏览器在后台异步处理控制台I/O能够提高性能,这时用户甚至可能根本意识不到其发生。所以
console.log()
到底是同步还是异步,取决于当前运行环境。解决方法
调试使用
debugger
或在console.log()
时,在外层包裹JSON.stringify()