关于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;

输出:

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

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

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

解决方法

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

© kaba 2019 - 2023