Chromeで確認しながらJS開発してたらconsole.logの出力ではまったので検証とメモ。
目的
console.logを実装している各ブラウザにおける、console.logの動作の違いを検証・理解する。
方法
以下は検証した方法。
環境
検証ブラウザは
Chrome 16.0.912.75
Firefox 9.0.1
Safari 5.1.2
である。
コード
検証コード。
console.log('#test1 start ----------');
var arr=[];
for(var i=0; i<3; i++){
console.log('i = '+i.toString());
arr.push(i);
console.log('arr = '+arr.toString());
console.log(arr);
}
console.log('#test2 start ----------');
var arr2=[];
for(var j=0; j<3; j++){
alert('');
console.log('j = '+j.toString());
arr2.push(j);
console.log('arr2 = '+arr2.toString());
console.log(arr2);
}
仮説
このコンソール出力は感覚的にはこうなりそう。
#test1 start ----------
i = 0
arr = 0
[0]
i = 1
arr = 0,1
[0, 1]
i = 2
arr = 0,1,2
[0, 1, 2]
#test2 start ----------
j = 0
arr2 = 0
[0]
j = 1
arr2 = 0,1
[0, 1]
j = 2
arr2 = 0,1,2
[0, 1, 2]
でもならない。
結果
以下ブラウザの結果。
Firefox
#test1 start ----------
i = 0
arr = 0
[0]
i = 1
arr = 0,1
[0, 1]
i = 2
arr = 0,1,2
[0, 1, 2]
#test2 start ----------
j = 0
arr2 = 0
[0]
j = 1
arr2 = 0,1
[0, 1]
j = 2
arr2 = 0,1,2
[0, 1, 2]
Safari
#test1 start ----------
i = 0
arr = 0
[0, 1, 2]
i = 1
arr = 0,1
[0, 1, 2]
i = 2
arr = 0,1,2
[0, 1, 2]
#test2 start ----------
j = 0
arr2 = 0
[0, 1, 2]
j = 1
arr2 = 0,1
[0, 1, 2]
j = 2
arr2 = 0,1,2
[0, 1, 2]
Chrome
#test1 start ----------
i = 0
arr = 0
[0, 1, 2]
i = 1
arr = 0,1
[0, 1, 2]
i = 2
arr = 0,1,2
[0, 1, 2]
#test2 start ----------
j = 0
arr2 = 0
[0]
j = 1
arr2 = 0,1
[0, 1]
j = 2
arr2 = 0,1,2
[0, 1, 2]
なんということでしょう。結果が全部違う。
ポイントをあげると
Firefox
・Firefoxの結果は一番感覚的にしっくりくる。
・ただしObjectを文字列として出力してるから中身は辿れない
Safari
・Objectの出力が、あとから更新されている
・そのためfor文で出力したArrayの内容が、全ての箇所で最後の状態になっている
・Objectの中身のObjectの中身も見れる
・でもやっぱり違和感がある
・バグだ!といいたいが仕様なのかもしれない(フォーラム漁ってない)
Chrome
・Objectの出力が、あとから更新されている
・そのためfor文で出力したArrayの内容が、全ての箇所で最後の状態になっている
・Objectの中身のObjectの中身も見れる
・というところまではSafariと一緒である
・ただ、console.logの合間にalertを挟むとFirefoxっぽく 結果が変わる
考察
参照を出力した場合の話は、Chromeに関してはChromiumのフォーラムを見ると
Javascript console.log does not log object instantly
にこの報告があがっていて、2011/8/1のものなんでしばらくこの状態だったみたい。全然気づかなかった。
また書き込みによるとどうやらバージョン13以降この仕様らしい。
確かに中身が見れる仕様だと、console.logのたびにディープコピーしまくらないといけないから難しいのかな?
そういう意味では、参照の出力が後から書き変わってしまうのは感覚的には違和感があるが仕様かもしれないし、あとSafariもそうなのでしかたないのかもしれない。
だが、上記仕様をやむをえないとするとしても、Chromeだけがalert挟むと結果が変わるのは、バグだろうと言いたい。
感想
フォーラムにあるように、自分でtoString()すればいいし、ブラウザごとのこの違いをあらかじめ知っていれば問題はそんなにないと思うが、僕は今まで知らなかったので何時間か悩みました。
あー。
と、ふと卒論を思い出して仮説検証型論文ぽく(見出しだけだけどw)した。