174 votes

La console JavaScript de Chrome est-elle paresseuse pour l'évaluation des tableaux?

Je vais commencer par le code:

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

Simple, non? En réponse à cela, Firebug dit:

 ["hi"]
["bye"]
 

Merveilleux, mais la console JavaScript de Chrome (version 7.0.517.41 bêta) dit:

 ["bye"]
["bye"]
 

Ai-je fait quelque chose de mal ou la console JavaScript de Chrome est-elle extrêmement paresseuse pour évaluer mon tableau?

95voto

Eric Mickelsen Points 6332

Merci pour le commentaire, tec. J'ai été en mesure de trouver un non confirmées Webkit bug qui explique ce problème: https://bugs.webkit.org/show_bug.cgi?id=35801

Il semble y avoir un débat au sujet de combien d'un bug c'est et si c'est réparable. Il semble y avoir un mauvais comportement pour moi. Il était particulièrement troublant pour moi, parce que, au Chrome, au moins, il se produit lorsque le code réside dans les scripts qui sont exécutés immédiatement (avant le chargement de la page), même lorsque la console est ouverte, à chaque fois que la page est actualisée. L'appel de la console.journal lorsque la console n'est pas encore actif seulement une référence à l'objet en cours en attente, pas la sortie de la console. Par conséquent, la matrice (ou un objet), ne seront pas évaluées jusqu'à ce que la console est prête. C'est vraiment un cas d'évaluation différée.

Cependant, il existe un moyen simple pour éviter ce dans votre code:

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

En appelant toString, vous créer une représentation en mémoire qui ne sera pas modifiée par les instructions suivantes, qui la console lira quand il est prêt. La sortie de la console est légèrement différente de passage de l'objet directement, mais il semble tout à fait acceptable:

hi
bye

30voto

動靜能量 Points 33008

D'après l'explication d'Eric, cela est dû au fait que console.log() est mis en file d'attente et qu'il affiche une valeur ultérieure du tableau (ou de l'objet).

Il peut y avoir 5 solutions:

 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
 

7voto

yingted Points 2444

Vous pouvez cloner un tableau avec Array#slice:

console.log(s); // ["bye"], i.e. incorrect
console.log(s.slice()); // ["hi"], i.e. correct

Une fonction que vous pouvez utiliser à la place de console.log qui n'ont pas ce problème est comme suit:

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

Pour le cas des objets, malheureusement, la meilleure méthode semble être de débogage d'abord avec un non-navigateur WebKit, ou d'écrire une fonction compliquée de clone. Si vous travaillez uniquement avec des objets simples, où l'ordre des touches n'est pas grave et il n'y a pas de fonctions, vous pouvez toujours le faire:

console.logSanitizedCopy = function () {
    var args = Array.prototype.slice.call(arguments);
    var sanitizedArgs = JSON.parse(JSON.stringify(args));

    return console.log.apply(console, sanitizedArgs);
};

Toutes ces méthodes sont évidemment très lent, donc, plus encore qu'avec la normale console.logs, vous avez à strip off après que vous avez terminé le débogage.

2voto

Shadow Wizard Points 38568

On dirait que Chrome remplace dans sa phase de "pré-compilation" toute instance de "s" par un pointeur sur le tableau actuel.

Une solution consiste à cloner le tableau, en enregistrant une nouvelle copie à la place:

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X