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。
它只实现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);
这已经在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; }