问题
最近在调试项目时,用console.log()打印一些数据,但打印出的数据却和期望值不太符合,导致找原因找了半天。
我做了个小例子,如下:
在Chrome控制台执行以下代码,发现,打印出来的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 是异步的错觉。
解决
我们可以利用 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}]
总结
- Chrome浏览器console.log()是同步的;
- 利用console.log()进行代码打印调试不可信。