事情是在最近的一次开发中发现一个诡异的问题,前端在操作某个对象时,发现在chrome下console出来的值和预期的结果不一致,然后就debugger看了一下却发现结果是对的。多次验证后发现debugger和console的值不一致,于是小小的探索了一番。
不多说上代码:
var obj = [{ 1: 1 }, { 2: 2 }, { 3: 3 }, { 4: 4 }]
console.log(obj)
obj.shift()
console.log(obj)
按照正常理解,你肯定会觉得what? 这么简单的code能有什么问题?我猜你会说结果是这样
//第一个console [{ 1: 1 }, { 2: 2 }, { 3: 3 }, { 4: 4 }]
//第二个console [{ 2: 2 }, { 3: 3 }, { 4: 4 }]一切似乎都在意料之中,却又往往超乎寻常,那我们来看看实际的效果吧
what?本切图仔多年的切图经验失效了???js的执行不是同步的?代码的执行顺序不是从右到左,从上到下????
一时间有点没有头绪。那么先打个debugger看看吧。
结果如下:
结果一切正常。于是陷入懵逼状态。。。。。
懵了2s,然后开始寻找问题根源,在确认代码没有写错,浏览器没有缓存等问题后开始尝试如下:
test1: 尝试将var改成const,控制台输出同上,排除变量定义问题。
const obj = [{ 1: 1 }, { 2: 2 }, { 3: 3 }, { 4: 4 }]
console.log(obj)
obj.shift()
console.log(obj)
test2: 尝试将obj里的值由复合数据类型改成基本数据类型
const obj = [1, 2, 3, 4]
console.log(obj)
obj.shift()
console.log(obj)控制台输出:
console出来的结果也对了,那么基本可以确定问题是出在数据类型上。而且基本数据类型是OK的,那么就是复合数据类型的问题了。联想到复合数据类型的引用属于地址引用,开始设想是地址引用造成了数据污染的问题,开始继续尝试
test2-1:尝试修改原数组之前将原数组备份一份
const obj = [{ 1: 1 }, { 2: 2 }, { 3: 3 }, { 4: 4 }]
const obj1 = obj.slice(0)
console.log(obj1)
obj.shift()
console.log(obj)控制台输出:
结果似乎是跟想象中的差差差差不多吧,但又感觉哪里怪怪的。继续尝试
test2-2:既然基础数据类型是可以的,那何不不对象的值改成基础数据类型
const obj = [{ 1: 1 }, { 2: 2 }, { 3: 3 }, { 4: 4 }]
console.log(JSON.stringify(obj))
obj.shift()
console.log(JSON.stringify(obj))控制台输出:
输出的结果是对了,貌似还是有点麻烦。
通过几次尝试,大致确认了问题所在,开始寻找问题的根源。
功夫不负有心人,好歹是面向搜索引擎的切图仔,貌似找到了一丢丢线索:
资料来源:segmentfault.com/a/119000001…
以下内容完全引自:《你不知道的javascript中卷》第二部分异步和性能 1.1 异步控制台部分
并没有什么规范或一组需求指定console.* 方法族如何工作——它们并不是JavaScript 正式的一部分,
而是由宿主环境(请参考本书的“类型和语法”部分)添加到JavaScript 中的。因此,不同的浏览器和JavaScript
环境可以按照自己的意愿来实现,有时候这会引起混淆。尤其要提出的是,在某些条件下,某些浏览器的console.log(..)
并不会把传入的内容立即输出。出现这种情况的主要原因是,在许多程序(不只是JavaScript)中,I/O 是非常
低速的阻塞部分。所以,(从页面/UI 的角度来说)浏览器在后台异步处理控制台I/O 能够提高性能,这时用户甚
至可能根本意识不到其发生。
书中建议:
如果遇到这种少见的情况,最好的选择是在JavaScript 调试器中使用断点,而不要依赖控制台输出。次优的方案
是把对象序列化到一个字符串中,以强制执行一次“快照”,比如通过JSON.stringify(..)
结论:通过一次诡异的问题,发现了一个之前很少注意到的一个点。吃一堑长一智,平常开发中还是要多注意,遇到问题了要细心调试查找,虽然可能暂时一头雾水,但是探索的过程才是乐趣所在啊。