Javascript 是Chrome';如何评估数组?

Javascript 是Chrome';如何评估数组?,javascript,arrays,logging,google-chrome,console,Javascript,Arrays,Logging,Google Chrome,Console,我将从代码开始: var s = ["hi"]; console.log(s); s[0] = "bye"; console.log(s); 很简单,对吧?对此,Firebug表示: ["hi"] ["bye"] 很好,但是Chrome的JavaScript控制台(7.0.517.41测试版)说: 我是否做错了什么,或者Chrome的JavaScript控制台在评估我的数组时异常懒惰 谢谢你的评论,tec。我能够找到一个现有的未经确认的Webkit bug来解释这个问题:(编辑:现已修复!)

我将从代码开始:

var s = ["hi"];
console.log(s);
s[0] = "bye";
console.log(s);
很简单,对吧?对此,Firebug表示:

["hi"]
["bye"]
很好,但是Chrome的JavaScript控制台(7.0.517.41测试版)说:

我是否做错了什么,或者Chrome的JavaScript控制台在评估我的数组时异常懒惰


谢谢你的评论,tec。我能够找到一个现有的未经确认的Webkit bug来解释这个问题:(编辑:现已修复!)

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

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

var s = ["hi"];
console.log(s.toString());
s[0] = "bye";
console.log(s.toString());
通过调用toString,您可以在内存中创建一个表示,该表示不会被以下语句更改,控制台将在准备就绪时读取这些语句。控制台输出与直接传递对象略有不同,但似乎可以接受:

hi
bye

看起来Chrome正在“预编译”阶段用指向实际数组的指针替换任何“s”实例

一种方法是克隆阵列,改为记录新副本:

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

function CloneArray(array)
{
    var clone = new Array();
    for (var i = 0; i < array.length; i++)
        clone[clone.length] = array[i];
    return clone;
}
var s=[“hi”];
控制台日志(CloneArray);
s[0]=“再见”;
控制台日志(CloneArray);
函数CloneArray(数组)
{
var clone=新数组();
对于(var i=0;i
您可以使用
数组#切片克隆数组

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.log更慢,调试完成后必须将它们去掉。

根据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

这已经得到了回答,但我还是放弃我的答案。我实现了一个简单的控制台包装器,它不会受到这个问题的影响。需要jQuery

它只实现了
log
warn
error
方法,您必须添加更多的方法才能与常规
控制台互换

var固定控制台;
(函数($){
var\u freezeOne=函数(arg){
if(typeof arg==='object'){
返回$.extend(true,{},arg);
}否则{
返回arg;
}
};
var\u freezeAll=函数(args){
var冻结=[];

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

console.log(JSON.stringify(the_array));

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

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

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

我在Safari中观察到了相同的行为——因此这可能是webkit的事情。非常令人惊讶。我称之为bug。对我来说,它看起来像bug。在Linux Opera和Firefox上显示expect结果是,Chrome和其他基于Webkit的浏览器没有。你可能想向Webkit开发者报告这个问题:截至2016年3月,这个问题已经不存在了。2020年4月,Chrome出现了这个问题。在我的代码中浪费了2个小时寻找一个错误,结果是Chrome中的一个错误。同样值得注意的是,蓝色的
i
图标的工具提示显示“下面的值刚刚计算过。”。事实上,对于关联数组或其他对象,这可能是一个真正的问题,因为toString不会产生任何有价值的东西。一般来说,有没有一个简单的方法可以解决对象的问题呢?webkit在几个月前就为这个问题找到了一个补丁。这样做:console.log(JSON.parse(JSON.stringify)(s));我只想指出,在当前的Chrome版本中,控制台被延迟,并且输出值再次出错(或者它是否正确)。例如,我记录了一个数组,并在记录后弹出最大值,但它显示时没有弹出值。您的toString()这个建议对于到达需要查看值的位置非常有用。使用
debugger;
从代码中插入断点也是一个很好的选择。(如果可行,也可以从开发人员工具中手动添加断点)。这很好,但因为它是一个浅拷贝,所以仍然有可能出现更微妙的问题。那么非数组的对象呢?(现在才是真正的问题。)我不认为您所说的“预编译”是准确的。另外,代码中有一个错误:clone[clone.length]应该是clone[I]。没有错误,我已经执行了它,它还可以。克隆[clone.length]与克隆[I]完全相同,因为数组的长度以0开头,循环迭代器“I”也是如此。无论如何,我不确定它在处理复杂对象时会如何运行,但在我看来值得一试。正如我所说,这不是解决方案,而是解决问题的方法。@Shadow Wizard:Good point:clone.length
console.log({...myObject});
console.log([...myArray]);