阅读 1791

console.log的输出真的可信吗

有许多坑可能真的需要自己去踩一踩😂,不得不说Javascript真的是一门神奇的语言~~;一些看起来习以为常的调用,往往得不到自己想要的结果,只能通过不断踩坑或者别人踩的坑积累经验值,来再次踩坑~~

背景

最近在调bug...由于涉及的链路比较长、多个项目之前通过postMessage来进行通信,首先想到的就是在JS调用链路中通过console.log输出状态变量,观察状态变量是在何时改变的,进行bug定位。

本来一个挺简单的bug,由于console.log的坑,导致在定位bug的路上进入了一个错误的方向,愣是多花了好久时间。最后还是在debugger的帮助下,成功解决了bug。

问题复现

首先来看一段代码

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" >
    <title>console.log测试</title>
  </head> 
  <body>
    <script>
      const obj = {
        name: 'Tom',
        height: 170,
      };
      console.log(obj);
      obj.height = 180;
    </script>
  </body>
</html>
复制代码

在浏览器控制台中,你认为会输出什么?如果没有踩这个坑之前我估计也会认为会输出这个结果:

{ name: 'Tom', height: 170 }
复制代码

然而,实际上:

image.png

是不是感觉像是薛定谔的猫,箱子没打开之前不知道里面是什么状态?

原因

我们知道JS里面分为基本类型和引用类型,具体每个类型的分类可以查看MDN,点击跳转。 我们在代码中调用console.log(obj), 其实就是把obj这个引用类型传给了console.log这个函数,只有这个函数真正用到obj内部属性的时候,才会去内存中查找对应的属性值

由于console.log并没有标准的实现规范,在chrome里是异步的,导致后面obj.height的赋值先与console.log对height属性的取值,这个顺序问题,造成了上述的问题。

解决办法

一般来说有两种方式可以解决这个问题:

  1. 使用同步的方式保存调用console.log时,obj的快照,比较典型的是使用深拷贝、JSON序列化的方式,这样在后续改变obj的属性也不会对console.log的调用造成影响

  2. 使用debugger的方式进行调试,不过在长链路的调试中,跳来跳去的调试略微有点麻烦😂

文章分类
前端
文章标签