为什么在第一个和第二个console.log()中我得到了相同的结果
在上面的代码中,问题出现在console.log
函数中。当我们尝试使用console.log
打印出一个数组时,如果我们直接传递数组作为参数,那么在控制台输出的结果将会是一个引用,而不是数组的副本。这意味着当我们修改原始数组时,控制台输出的结果也会随之改变。
为了解决这个问题,我们可以使用Array#slice
方法来克隆一个数组。在console.log
中使用slice
方法可以得到正确的结果。
除了使用slice
方法克隆数组之外,我们还可以使用一个自定义的函数console.logShallowCopy
来代替console.log
。这个函数可以避免上述问题的发生。它会将传入的参数进行克隆,然后再调用console.log
来输出结果。
对于对象来说,要想克隆一个对象就比较困难了。在非WebKit浏览器中调试或者编写一个复杂的克隆函数可能是最好的方法。如果你只使用简单的对象,其中键的顺序不重要且没有函数,那么你可以使用console.logSanitizedCopy
函数。这个函数会先将参数转换成JSON字符串,再将其转换回对象,从而实现克隆的效果。
需要注意的是,所有这些方法都会导致性能下降,所以在调试完成后,应该及时移除这些方法。
为了解决在调试过程中console.log
输出相同结果的问题,我们可以使用Array#slice
方法克隆数组,或者使用自定义的console.logShallowCopy
函数克隆参数。对于对象,使用console.logSanitizedCopy
函数可以实现克隆。在使用完这些方法后,需要及时移除以提高性能。
为什么我在第一个和第二个console.log()中得到相同的结果?
从Eric的解释中可以得知,这是由于console.log()被排队处理,它会打印数组(或对象)的后续值。
有以下5种解决方案:
1. arr.toString() // 对于[1,[2,3]]不适用,因为它会显示1,2,3
2. arr.join() // 与上述相同
3. arr.slice(0) // 创建一个新数组,但如果arr是[1, 2, arr2, 3],并且arr2发生变化,则可能显示后续值
4. arr.concat() // 创建一个新数组,但与slice(0)相同的问题
5. JSON.stringify(arr) // 这个方法很好,它会对整个数组或对象进行快照,并以精确的结构显示
任何复制列表/对象的解决方案都可以使用。我最喜欢的浅拷贝对象的方法是在ECMAScript 2018中引入的:copy = {...orig}。值得一提的是,浅拷贝会将数组转换为对象。
为什么在第一次和第二次console.log()中得到相同的结果?
在这个问题中,有一个已知的未经确认的Webkit bug,可以解释这个问题的出现:https://bugs.webkit.org/show_bug.cgi?id=35801(已修复!)。关于这个bug有一些争论,争论的焦点在于这是否算是一个bug以及是否可以修复。对我来说,这似乎是一个不好的行为。尤其让我感到困扰的是,在Chrome中,无论控制台是否打开,只要页面刷新,这个问题就会发生,即使代码位于立即执行的脚本中(在页面加载之前)。在控制台尚未激活时调用console.log只会导致对该对象的引用被排队,而不是控制台中的输出。因此,数组(或任何对象)只有在控制台准备好之后才会被评估。这确实是一种懒惰评估。
然而,有一个简单的方法可以避免这个问题:
var s = ["hi"];
console.log(s.toString());
s[0] = "bye";
console.log(s.toString());
通过调用toString,您可以创建一个在内存中表示的表示形式,这个表示形式不会被后续语句更改,而控制台在准备好时会读取它。控制台输出与直接传递对象略有不同,但似乎可以接受:
hi
bye
实际上,对于关联数组或其他对象,这可能是一个真正的问题,因为toString不会产生任何有价值的内容。是否有一个简单的解决方案适用于一般的对象?
webkit几个月前已经解决了这个问题。
可以这样做:console.log(JSON.parse(JSON.stringify(s));
我只想提一下,在当前版本的Chrome中,控制台是延迟的,并且错误地输出值(或者它从来没有正确输出过)。例如,我在记录一个数组并在记录后弹出数组的顶部值,但它显示的是没有弹出值的数组。您的toString()建议在我需要查看值时非常有用。
还有一个很好的选择是从代码中插入一个断点,使用debugger;。如果可行的话,也可以手动从开发者工具中添加断点。