Неужели консоль JavaScript в Chrome ленилась оценивать массивы? - PullRequest
111 голосов
/ 30 октября 2010

Начну с кода:

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

Просто, верно? В ответ на это Firebug говорит:

["hi"]
["bye"]

Замечательно, но консоль Chrome JavaScript (7.0.517.41 бета) говорит:

["bye"]
["bye"]

Я что-то не так сделал или консоль JavaScript в Chrome исключительно ленива при оценке моего массива?

enter image description here

Ответы [ 7 ]

57 голосов
/ 30 октября 2010

Спасибо за комментарий, тек.Мне удалось найти существующую неподтвержденную ошибку 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
17 голосов
/ 08 октября 2012

По объяснению Эрика, это связано с тем, что 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
6 голосов
/ 27 января 2011

Вы можете клонировать массив с помощью 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.log s, вы должны удалить их после завершения отладки.

2 голосов
/ 30 апреля 2015

Это было исправлено в Webkit, однако при использовании инфраструктуры React это происходит для меня в некоторых обстоятельствах, если у вас возникают такие проблемы, просто используйте, как другие предлагают:

console.log(JSON.stringify(the_array));
1 голос
/ 28 февраля 2013

На это уже есть ответ, но я все равно оставлю свой ответ.Я реализовал простую консольную оболочку, которая не страдает от этой проблемы.Требуется 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);
0 голосов
/ 01 апреля 2019

Принцип работы console.log не стандартизирован, поэтому в некоторых случаях некоторые браузеры будут задерживать console.log по соображениям производительности.

Однако странно, что это происходит по такой простой причине.

0 голосов
/ 31 октября 2010

Похоже, что 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...