Chrome 的 JavaScript 控制台是否懒得评估数组?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4057440/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is Chrome's JavaScript console lazy about evaluating arrays?
提问by Eric Mickelsen
I'll start with the code:
我将从代码开始:
var s = ["hi"];
console.log(s);
s[0] = "bye";
console.log(s);
Simple, right? In response to this, Firebug says:
很简单吧?对此,Firebug 表示:
["hi"]
["bye"]
Wonderful, but Chrome's JavaScript console (7.0.517.41 beta) says:
很棒,但是 Chrome 的 JavaScript 控制台(7.0.517.41 beta)说:
["bye"]
["bye"]
Have I done something wrong, or is Chrome's JavaScript console being exceptionally lazy about evaluating my array?
我做错了什么,还是 Chrome 的 JavaScript 控制台对评估我的数组非常懒惰?
采纳答案by Eric Mickelsen
Thanks for the comment, tec. I was able to find an existing unconfirmed Webkit bug that explains this issue: https://bugs.webkit.org/show_bug.cgi?id=35801(EDIT: now fixed!)
感谢您的评论,技术。我能够找到一个现有的未经证实的 Webkit 错误来解释这个问题:https: //bugs.webkit.org/show_bug.cgi?id =35801(编辑:现已修复!)
There appears to be some debate regarding just how much of a bug it is and whether it's fixable. It does seem like bad behavior to me. It was especially troubling to me because, in Chrome at least, it occurs when the code resides in scripts that are executed immediately (before the page is loaded), even when the console is open, whenever the page is refreshed. Calling console.log when the console is not yet active only results in a reference to the object being queued, not the output the console will contain. Therefore, the array (or any object), will not be evaluated until the console is ready. It really is a case of lazy evaluation.
关于它有多少错误以及它是否可以修复,似乎存在一些争论。在我看来,这确实是一种不良行为。这对我来说尤其令人不安,因为至少在 Chrome 中,当代码驻留在立即执行的脚本中时(在页面加载之前),即使在控制台打开时,只要刷新页面,就会发生这种情况。当控制台尚未激活时调用 console.log 只会导致对正在排队的对象的引用,而不是控制台将包含的输出。因此,在控制台准备好之前,不会评估数组(或任何对象)。这确实是一个懒惰评估的情况。
However, there is a simple way to avoid this in your code:
但是,有一种简单的方法可以在您的代码中避免这种情况:
var s = ["hi"];
console.log(s.toString());
s[0] = "bye";
console.log(s.toString());
By calling toString, you create a representation in memory that will not be altered by following statements, which the console will read when it is ready. The console output is slightly different from passing the object directly, but it seems acceptable:
通过调用 toString,您可以在内存中创建一个表示,该表示不会被以下语句更改,控制台将在准备好时读取该表示。控制台输出与直接传递对象略有不同,但似乎可以接受:
hi
bye
回答by nonopolarity
From Eric's explanation, it is due to console.log()
being queued up, and it prints a later value of the array (or object).
从 Eric 的解释来看,是由于console.log()
排队,所以打印了数组(或对象)的后一个值。
There can be 5 solutions:
可能有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
回答by yingted
You can clone an array with Array#slice
:
您可以使用以下命令克隆数组Array#slice
:
console.log(s); // ["bye"], i.e. incorrect
console.log(s.slice()); // ["hi"], i.e. correct
A function that you can use instead of console.log
that doesn't have this problem is as follows:
您可以使用的函数而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);
};
For the case of objects, unfortunately, the best method appears to be to debug first with a non-WebKit browser, or to write a complicated function to clone. If you are only working with simple objects, where order of keys doesn't matter and there are no functions, you could always do:
不幸的是,对于对象的情况,最好的方法似乎是首先使用非 WebKit 浏览器进行调试,或者编写一个复杂的函数来克隆。如果您只使用简单的对象,其中键的顺序无关紧要并且没有功能,您总是可以这样做:
console.logSanitizedCopy = function () {
var args = Array.prototype.slice.call(arguments);
var sanitizedArgs = JSON.parse(JSON.stringify(args));
return console.log.apply(console, sanitizedArgs);
};
All of these methods are obviously very slow, so even more so than with normal console.log
s, you have to strip them off after you're done debugging.
所有这些方法显然都非常慢,所以比普通console.log
s更慢,你必须在完成调试后将它们剥离。
回答by justinsAccount
This has been patched in Webkit, however when using the React framework this happens for me in some circumstances, if you have such problems just use as others suggest:
这已在 Webkit 中进行了修补,但是在使用 React 框架时,在某些情况下会发生这种情况,如果您遇到此类问题,请按照其他人的建议使用:
console.log(JSON.stringify(the_array));
回答by wrygiel
This is already answered, but I'll drop my answer anyway. I implemented a simple console wrapper which doesn't suffer from this issue. Requires jQuery.
这已经得到了回答,但无论如何我都会放弃我的回答。我实现了一个简单的控制台包装器,它不会遇到这个问题。需要 jQuery。
It implements only log
, warn
and error
methods, you will have to add some more in order for it to be interchangeable with a regular console
.
它仅实现log
,warn
和error
方法,你将不得不增加一些,以便它是一个普通互换console
。
var fixedConsole;
(function($) {
var _freezeOne = function(arg) {
if (typeof arg === 'object') {
return $.extend(true, {}, arg);
} else {
return arg;
}
};
var _freezeAll = function(args) {
var frozen = [];
for (var i=0; i<args.length; i++) {
frozen.push(_freezeOne(args[i]));
}
return frozen;
};
fixedConsole = {
log: function() { console.log.apply(console, _freezeAll(arguments)); },
warn: function() { console.warn.apply(console, _freezeAll(arguments)); },
error: function() { console.error.apply(console, _freezeAll(arguments)); }
};
})(jQuery);
回答by Shadow Wizard is Ear For You
Looks like Chrome is replacing in its "pre compile" phase any instance of "s" with pointerto the actual array.
看起来 Chrome 正在其“预编译”阶段用指向实际数组的指针替换“s”的任何实例。
One way around is by cloning the array, logging fresh copy instead:
一种解决方法是克隆数组,而不是记录新副本:
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;
}
回答by ptica
the shortest solution so far is to use array or object spread syntax to get a clone of values to be preserved as in time of logging, ie:
迄今为止最短的解决方案是使用数组或对象传播语法来获取要在记录时保留的值的克隆,即:
console.log({...myObject});
console.log([...myArray]);
however be warned as it does a shallow copy, so any deep nested non-primitive values will not be cloned and thus shown in their modified state in the console
但是要注意,因为它是浅拷贝,所以任何深层嵌套的非原始值都不会被克隆,因此不会在控制台中以修改后的状态显示