别再用console.log调试代码了(血泪教训)

689 阅读2分钟

问题

最近在调试项目时,为了图方便,我用console.log()打印了一些数据用于调试,但打印出的数据却和期望值不太符合,我误以为是代码写错了,导致花了大量精力来找原因。最后才知道问题是出在console.log()上。 错付了....

为此我做了个小例子来演示,如下:

在Chrome控制台执行以下代码,
我原本以为打印出来a的值会分别为1、2、3;
结果,打印出来的a的值都为3。
为何会这样?难道console.log()是异步执行的?

let arr = [];
let obj = {a:1};
arr.push(obj);
console.log(arr);
obj.a=2;
console.log(arr);
let obj1 = obj;
obj1.a=3;
console.log(arr);
//[{"a":3}]
//[{"a":3}]
//[{"a":3}]

在这里插入图片描述

我又试了试在node环境执行同样的代码,输出却是:

[ { a: 1 } ]
[ { a: 2 } ]
[ { a: 3 } ]

我就懵了,为啥会这样。。。

分析

首先可以确定的是console.log 是同步
出现这种情况的原因是:

WebKit的console.log并没有立即拍摄对象快照,相反,它只存储了一个指向对象的引用,然后在代码返回事件队列时才去拍摄快照。 ---《JavaScript异步编程》

也就是说,在以WebKit为内核的Chrome浏览器中,它的控制台对应引用类型的数据读取是默认值读取一层数据,当你点击展开时,会再去堆内存中读取属性值和下一层的数据。

这种出于性能优先的考虑有时候会给我们一种console.log 是异步的错觉。
同时也体现出了利用console.log来调试是不可靠的...(吸取了教训)

解决

我们可以利用 JSON.stringify(object) 将对象序列化到一个字符串中,以强制执行一次“快照”:

let arr = []; 
let obj = {a:1}; 
arr.push(obj); 
console.log(JSON.stringify(arr)); 
obj.a=2; 
console.log(JSON.stringify(arr)); 
let obj1 = obj; 
obj1.a=3; 
console.log(JSON.stringify(arr));
//[{"a":1}]
//[{"a":2}]
//[{"a":3}]

最好还是直接用debugger进行调试吧。

总结

  • Chrome浏览器console.log()是同步的;
  • 利用console.log()进行代码打印调试不可信。
  • 调试还是用debugger吧