Chrome的JavaScript控制台懒惰评估数组?

我将从代码开始:

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

很简单,对吧? 对此,Firebug说:

 ["hi"] ["bye"] 

精彩,但Chrome的JavaScript控制台(7.0.517.41testing版)说:

 ["bye"] ["bye"] 

我做错了什么,或者是Chrome的JavaScript控制台对于评估我的数组非常懒惰?

感谢您的评论,技术。 我能find一个解决这个问题的现有未经证实的Webkit错误: https : //bugs.webkit.org/show_bug.cgi? id = 35801 (编辑:现在修正了!)

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

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

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

通过调用toString,你可以在内存中创build一个不会被后面的语句改变的表示,控制台在准备好时会读取它。 控制台输出与直接传递对象稍有不同,但似乎可以接受:

 hi bye 

从埃里克的解释,这是由于console.log()被排队,并打印数组(或对象)的更高的价值。

可以有5个解决scheme:

 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 

您可以使用Array#slice克隆数组:

 console.log(s); // ["bye"], ie incorrect console.log(s.slice()); // ["hi"], ie 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浏览器进行debugging,或者编写一个复杂的函数来克隆。 如果你只使用简单的对象,键的顺序无关紧要,并且没有任何function,你总是可以这样做:

 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更加重要,你必须在完成debugging之后将它们去掉。

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

它只实现logwarnerror方法,你将不得不增加一些,以便它可以与一个普通的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); 

这已经在Webkit中进行了修补,但是在使用React框架时,在某些情况下,这会发生在我身上,如果您遇到这样的问题,请使用其他人的build议:

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

看起来像Chrome正在取代“预编译”阶段的任何“s”的实例与指向实际数组的指针

一个办法是克隆数组,然后logging新鲜的副本:

 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; }