Chrome 的 JavaScript 控制台是否懒得评估数组?

IT技术 javascript arrays logging google-chrome console
2020-12-28 23:05:32

我将从代码开始:

var s = ["hi"];
console.log(s);
s[0] = "bye";
console.log(s);

很简单吧?对此,Firebug 表示:

["hi"]
["bye"]

很棒,但是 Chrome 的 JavaScript 控制台(7.0.517.41 beta)说:

["bye"]
["bye"]

我做错了什么,还是 Chrome 的 JavaScript 控制台在评估我的数组时非常懒惰?

在此处输入图片说明

6个回答

感谢您的评论,技术。我能够找到一个现有的未经证实的 Webkit 错误来解释这个问题:https : //bugs.webkit.org/show_bug.cgi? id =35801(编辑:现已修复!)

关于它有多少错误以及它是否可以修复,似乎存在一些争论。在我看来,这确实是一种不良行为。这对我来说尤其令人不安,因为至少在 Chrome 中,当代码驻留在立即执行的脚本中时(在页面加载之前),即使在控制台打开时,只要刷新页面,就会发生这种情况。当控制台尚未激活时调用 console.log 只会导致对正在排队的对象的引用,而不是控制台将包含的输出。因此,在控制台准备好之前,不会评估数组(或任何对象)。这确实是一个懒惰评估的情况。

但是,有一种简单的方法可以在您的代码中避免这种情况:

var s = ["hi"];
console.log(s.toString());
s[0] = "bye";
console.log(s.toString());

通过调用 toString,您可以在内存中创建一个表示,该表示不会被以下语句更改,控制台将在准备好时读取该表示。控制台输出与直接传递对象略有不同,但似乎可以接受:

hi
bye
几个月前,webkit 为此发布了一个补丁
2021-02-12 23:05:32
这样做: console.log(JSON.parse(JSON.stringify(s));
2021-02-18 23:05:32
实际上,对于关联数组或其他对象,这可能是一个真正的问题,因为 toString 不会产生任何有value的东西。一般来说,是否有针对对象的简单解决方法?
2021-03-02 23:05:32
从代码中插入断点debugger;也是一个不错的选择。(或者,如果可行,从开发人员工具手动添加断点)。
2021-03-02 23:05:32
我只想提一下,在当前的 Chrome 版本中,控制台被延迟并再次输出错误的值(或者它曾经是对的)。例如,我正在记录一个数组并在记录后弹出最高值,但它显示时没有弹出值。您的 toString() 建议对于到达我需要查看值的位置非常有帮助。
2021-03-05 23:05:32

从 Eric 的解释来看,是由于console.log()排队,所以打印了数组(或对象)的后一个值。

可能有5种解决方案:

1. arr.toString()   // not well for [1,[2,3]] as it shows 1,2,3
2. arr.join()       // same as above
3. arr.slice(0)     // a new array is created, but if arr is [1, 2, arr2, 3] 
                    //   and arr2 changes, then later value might be shown
4. arr.concat()     // a new array is created, but same issue as slice(0)
5. JSON.stringify(arr)  // works well as it takes a snapshot of the whole array 
                        //   or object, and the format shows the exact structure
任何复制列表/对象的解决方案都可以使用。自 ECMAScript 2018 以来,我最喜欢的对象浅拷贝可用:copy = {...orig}
2021-02-15 23:05:32

您可以使用以下命令克隆数组Array#slice

console.log(s); // ["bye"], i.e. incorrect
console.log(s.slice()); // ["hi"], i.e. correct

您可以使用的函数而console.log不是没有这个问题的函数如下:

console.logShallowCopy = function () {
    function slicedIfArray(arg) {
        return Array.isArray(arg) ? arg.slice() : arg;
    }

    var argsSnapshot = Array.prototype.map.call(arguments, slicedIfArray);
    return console.log.apply(console, argsSnapshot);
};

不幸的是,对于对象的情况,最好的方法似乎是首先使用非 WebKit 浏览器进行调试,或者编写一个复杂的函数进行克隆。如果您只使用简单的对象,其中键的顺序无关紧要并且没有功能,您总是可以这样做:

console.logSanitizedCopy = function () {
    var args = Array.prototype.slice.call(arguments);
    var sanitizedArgs = JSON.parse(JSON.stringify(args));

    return console.log.apply(console, sanitizedArgs);
};

所有这些方法显然都非常慢,所以比普通console.logs更慢,你必须在完成调试后将它们剥离。

这已在 Webkit 中进行了修补,但是在使用 React 框架时,在某些情况下会发生这种情况,如果您遇到此类问题,请按照其他人的建议使用:

console.log(JSON.stringify(the_array));
可以确认。当尝试注销 ReactSyntheticEvents 时,这实际上是最糟糕的。即使 aJSON.parse(JSON.stringify(event))也没有得到正确的深度/精度。调试器语句是我发现的唯一能够获得正确洞察力的真正解决方案。
2021-03-02 23:05:32

到目前为止,最短的解决方案是使用数组或对象传播语法来获取要在记录时保留的值的克隆,即:

console.log({...myObject});
console.log([...myArray]);

但是要注意,因为它是浅拷贝,因此任何深层嵌套的非原始值都不会被克隆,因此不会在控制台中以修改后的状态显示