console.log打印内容不一定可信

今天在工作中遇到的,使用console.log()输出 对象 信息时,出现输出的信息跟自己想的不一样的问题,着实让人诧异。便去查了一下,终于知道了原因,这里留作记录
参考https://github.com/Mmzer/think/issues/30

问题示例:

执行如下代码

let obj={age:20}
console.log(obj)
obj.age=30

得到结果

可以看到,不展开obj对象,看到的是我们预期的20,展开对象,看到的却是30。如果我们输出一个字段很多的对象,那必须展开才能看到属性值,否则就会被非预期的属性值误导。





原因分析:

  • 不展开对象看时,console.log()是按照代码执行顺序,同步地输出了对象当时的快照。所以我们看到的是预期的值。
  • 展开对象时,它其实是重新去内存中读取对象的属性值,此时对象属性已被更改,所以展开对象后,可能看到的不是预期值了。





浏览器或者开发者工具(F12)为什么出现这种情况?

这个问题,在《你不知道的javascript中卷》第二部分异步和性能1.1节一部控制台部分有提及:

并没有什么规范或一组需求指定console.* 方法族如何工作——它们并不是JavaScript 正式的一部分,而是由宿主环境(请参考本书的“类型和语法”部分)添加到JavaScript 中的。
因此,不同的浏览器和JavaScript 环境可以按照自己的意愿来实现,有时候这会引起混淆。
尤其要提出的是,在某些条件下,某些浏览器的console.log(..) 并不会把传入的内容立即输出。
出现这种情况的主要原因是,在许多程序(不只是JavaScript)中,I/O 是非常低速的阻塞部分。
所以,(从页面/UI 的角度来说)浏览器在后台异步处理控制台I/O 能够提高性能,这时用户甚至可能根本意识不到其发生。





总结

  • console.log()打印出来的内容并不是一定百分百可信的内容。一般对于基本类型number、string、boolean、null、undefined的输出是可信的。但对于Object等引用类型来说,则就会出现上述异常打印输出。
  • 尽量不要直接输出对象,先将对象序列化JSON.stringify()为字符串再输出
  • 最好使用打断点(debugger)的方式来调试。
posted @ 2019-12-04 09:10  huihuihero  阅读(387)  评论(0编辑  收藏  举报