天天看点

console.log的快照

        在日常开发中,我们经常使用console.log来打印数据进行调试,但是console.log的输出值有时候也不完全准确,或者说并不会达到我们预期的效果

举个例子(1):

var obj = {}

obj.a = 3;

console.log(obj); // {a:3}
           

当我们在script中编写如下代码,浏览器中会照常打印出我们所期望的数据

但是如果我们这样呢(2):

var obj = {}
queueMicrotask(()=>{
       obj.a = 3;
});
console.log(obj); 
           

当我们在浏览器中查看的时候,我们会看到这样的景象:

console.log的快照

但是当我们展开之后呢?

console.log的快照

?这是为什么?

这就和console.log的打印机制有关系了

1、案例(1)中代码是这样运行的:

  • 我们创建了一个对象,并且这个对象在内存中的引用地址赋值给了obj
  • 然后我们修改了obj.a = 3,内存地址中的a的值会被设置为3
  • 这个时候,我们使用console.log(obj),console.log会根据obj保存的内存地址去找到obj,最后打印
  • 在浏览器中正常输出

2、案例(2)中代码是这样运行的:

  • 我们创建了一个对象,并且这个对象在内存中的引用地址赋值给了obj
  • 然后解析到了queueMicrotask函数,将回调函数添加到了微任务队列中,等待同步代码执行完成,JS引擎才会执行微任务队列中的回调
  • console.log(obj),根据obj的内存地址去寻找,由于我们修改obj.a的代码为一个微任务,所以其实obj现在是一个空对象,再加上我们是立刻执行的一个console.log(),那么控制台将会输出一个空对象{}
  • 同步代码执行完成
  • 开始执行微任务队列,执行obj.a = 3,obj内存地址中的a被修改为3
  • 这个时候我们去查看控制台,我们就会看到打印的是那个空对象,因为我们打印的其实是console.log的快照!
  • 当我们点击控制台的展开的时候,浏览器又会根据obj保存的内存地址去寻找堆内存中的值,最后,我们就会看到一个被异步(微任务)修改的a:3,

其实总结起来很简单:

javascript的异步代码会被添加到任务队列中(宏/微),当我们修改值的代码写在一个异步函数内,console.log不会等待你的异步函数执行完成,它是优先执行的,然后输出空,然后你的异步函数又修改了obj的内存地址中的a,但是console.log已经执行完成了,不会重复执行,所以你看到的还是一个{}对象,但是当我们点击展开的时候,浏览器又会根据Obj的内存地址去找到他的值,最后打印,但是这个时候,你的obj中的a已经被修改为了3,所以会打印3

继续阅读