遇到的坑
今天在调试接口的时候发现一个奇怪的问题:同一个接口同一个用户同一个环境在两个项目中返回的结果不一样。遇到这种情况当然是要把锅甩出去咯,我就把流水拿给了后端同学让帮忙查一下,后端同学竟然说两条请求返回的结果是一样的。诶这就很奇怪了,我明明看console打印出来的日志是不一样。奇怪之下我开始打断点去调试,发现后端返回回来的结果确实是一样的,是前端和console工具共同的问题造成了这个结果。先看表现是怎样的:
1 | var a = {a: 1} |
这应该是控制在输出log的时候,其实是只保存了一个a的引用,当鼠标要展开这个对象时,再去调用getter方法去目标对象中取值,为了验证这个想法,我利用Object.defineProperty方法去定义一个对象:
1 | // 方案1 |
从上面两个代码我们就发现,确实当console打印出来时,他只保留了一个对象的引用,当真正展开去查看对象时才去调用getter方法取值。那是每次展开对象时都会去取值嘛?
1 | var a = {a: 1} |
所以我们发现只有第一次展开对象的时候会去getter他的值,后面收起就真的只是收起来了,再次展开也只是展开对象不会再次去取值。
所以,为什么会出现最开始调试时的那个问题。是因为请求回来之后操作改变了console引用对象的值,导致我们在查看对象时已经不是最初的返回结果了。那其实这样也不是我们理想当中状态,我们console就是为了输出当时的状态,而不是后面更改过的状态。
解决
知道了问题的原因,解决方案其实就是在打印的时候去拷贝一个对象,或者是在返回后不要修改console的对象。我的方法是用了lodash中的拷贝方法,console一个拷贝出来的对象。
1 | const _response = _.cloneDeep(response) |
还有一种比较简单的深复制方法:var newObject = JSON.parse(JSON.stringify(oldObject));
当然这个方法有一些局限性,比如:如果被拷贝的对象中有function,则拷贝之后的对象就会丢失这个function,如果被拷贝的对象中有正则表达式,则拷贝之后的对象正则表达式会变成Object。
1 | let a = { |
console的作用
前端调试中离不开console命令,主要是用来记录打印日志便于前端调试,其实console还有一些其他的妙用,比如计数(count)、计时(time)、断言(assert)等等功能,具体可以看以下的文章来学习:
*当时搜索时还发现,console.dir在firefox浏览器上会输出对象当前的一个副本,不会因为后面对象的改变而改变,但是这个在chrome当中却没有效果。
延伸
- 你所不知道的JSON.stringify 你所不知道的JSON.stringify
- 深浅拷贝 深入剖析 JavaScript 的深复制