私はコードから始めます:
var s = ["hi"];
console.log(s);
s[0] = "bye";
console.log(s);
シンプルでしょ?これに対して、Firebugは次のように述べています。
["hi"]
["bye"]
すばらしいですが、ChromeのJavaScriptコンソール(7.0.517.41ベータ版)は次のように述べています:
["bye"]
["bye"]
何か間違ったことをしたことがありますか、それともChromeのJavaScriptコンソールが配列の評価に関して非常に怠けているのですか?
コメントありがとう、tec。この問題を説明する既存の未確認の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
Ericの説明から、それは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
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を使用する場合よりもさらに、デバッグの完了後にそれらを削除する必要があります。
これはWebkitでパッチされていますが、Reactフレームワークを使用する場合、状況によってはこれが発生します。
console.log(JSON.stringify(the_array));
これはすでに回答されていますが、とにかく回答を破棄します。この問題の影響を受けないシンプルなコンソールラッパーを実装しました。 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);
Chromeは、 "pre compile"フェーズで、 "s"のインスタンスをpointerで実際の配列に置き換えています。
1つの方法は、代わりに新しいコピーを記録して、アレイを複製することです。
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;
}