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

Je vais commencer par le code:

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

Simple, n'est-ce pas? En réponse à cela, Firebug dit:

 ["hi"] ["bye"] 

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

 ["bye"] ["bye"] 

Ai-je fait quelque chose qui ne va pas, ou la console JavaScript de Chrome est-elle exceptionnellement paresseuse quant à l'évaluation de mon tableau?

    Merci pour le commentaire, tec. J'ai pu trouver un bug webkit non confirmé existant qui explique ce problème: https://bugs.webkit.org/show_bug.cgi?id=35801 (EDIT: now fixed!)

    Il semble y avoir un certain débat quant à la quantité d'un bug, et s'il est réglable. Cela me semble être un mauvais comportement. Cela m'était particulièrement troublant car, au moins dans Chrome, il se produit lorsque le code réside dans les scripts qui sont exécutés immédiatement (avant que la page ne soit chargée), même lorsque la console est ouverte, chaque fois que la page est actualisée. L'appel de console.log lorsque la console n'est pas encore active ne donne qu'une référence à l'objet mis en file d'attente et non à la sortie que la console contiendra. Par conséquent, le tableau (ou tout objet) ne sera évalué que lorsque la console est prête. C'est vraiment un cas d'évaluation paresseuse.

    Cependant, il existe un moyen simple d'éviter cela dans votre code:

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

    En appelant toString, vous créez une représentation en mémoire qui ne sera pas modifiée par les instructions suivantes, que la console lira quand elle est prête. La sortie de la console est légèrement différente de la transmission de l'objet directement, mais cela semble acceptable:

     hi bye 

    De l'explication d'Eric, il est dû à la console.log() en attente, et elle imprime une valeur ultérieure du tableau (ou 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 

    Vous pouvez cloner un tableau avec une Array#slice

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

    Une fonction que vous pouvez utiliser au lieu de console.log qui n'a pas ce problème est la suivante:

     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éboguer d'abord avec un navigateur non WebKit, ou d'écrire une fonction compliquée pour cloner. Si vous travaillez uniquement avec des objets simples, où l'ordre des clés n'a pas d'importance et il n'y a pas de fonctions, vous pouvez toujours 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 lentes, donc plus encore qu'avec la console.log s normale, il faut les retirer après que vous avez terminé le débogage.

    Ceci est déjà répondu, mais je vais laisser tomber ma réponse de toute façon. J'ai implémenté une enveloppe de console simple qui ne souffre pas de ce problème. Nécessite jQuery.

    Il implémente uniquement log méthodes de log , d' warn et d' error , vous devrez en ajouter davantage pour pouvoir être interchangeables avec une console régulière.

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

    Cela a été corrigé dans Webkit, cependant, lorsque vous utilisez le cadre React, cela m'arrive dans certaines circonstances, si vous avez de tels problèmes, utilisez simplement comme d'autres suggèrent:

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

    On dirait que Chrome remplaçait dans sa phase "précompilation" toute instance de "s" avec pointeur vers le tableau réel.

    Un moyen est de cloner le tableau, en annulant 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; }