Skip to content
kaba

关于Console.log

JavaScript1 min read

最近在帮同学调试问题的时候,console.log()的输出真是震惊我,居然出现了类似异步输出的表现,直接把我带偏了,于是我查阅了资料,并将其记录下来。

问题本身:
1function Fn(){
2 this.a =1;
3 this.__proto__.b =2
4}
5 let fn2 = new Fn();
6 let fn3 = new Fn();
7 console.log(fn2.__proto__.b)
8 console.log(fn2)
9 console.log(fn3.__proto__.b)
10 console.log(fn3)
11 fn3.__proto__.b =3;
输出:

image-20210207200926013 可以看到fn2和fn3的proto.b和期望输出的值是一样的,而当把fn2和fn3展开后: image-20210207200940809 他们的值都从2变成了3

为什么会出现这样的原因呢

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

解决方法

调试使用debugger 或在console.log()时,在外层包裹JSON.stringify()