问题
最近在调试项目时,为了图方便,我用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吧