概要
ブラウザでJavaScriptを実行している時にconsole.log
に参照型のデータを渡して出力すると期待通りに出力されない場合があります。その再現手順と回避策を記します。
ソースコード
今回使用するソースコードは以下の2ファイルです。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>console-log-sample</title>
</head>
<body>
<script src="./main.js"></script>
</body>
</html>
'use strict';
class Name {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
class Human {
constructor(name, age, address1, address2) {
this.name = name;
this.age = age;
}
}
const name = new Name('太郎', '佐藤');
const human = new Human(name, 25);
console.log(human); // firstName が 太郎, lastName が 佐藤, age が 25 と出力して欲しい
human.name = new Name('次郎', '鈴木');;
human.age = 30;
console.log(human); // firstName が 次郎, lastName が 鈴木, age が 30 と出力して欲しい
ブラウザ(Chrome)で実行した場合の出力結果
index.html
をブラウザで表示したときのコンソール出力結果は画像の通りです。
age
は期待通りに出力できていますね。name
の中身を確認するために展開してみましょう。
展開してみると、1つ目のconsole.log
結果と2つ目のconsole.log
結果が同じ値になっています。どうやら後から代入した値が出力されているようですね。
なぜこんな現象が発生するのでしょうか。これについてはMDNのドキュメントに記載がありました。
出力する JavaScript オブジェクトのリスト。各オブジェクトの文字列表現が記述順で出力されます。
Chrome や Firefox の比較的新しいバージョンを使っているなら注意が必要です。
これらのブラウザーで記録されるのはオブジェクトへの参照です。そのため、 console.log() を呼び出した時点でのオブジェクトの「値」が表示されるのではなく、内容を見るために開いた時点での値が表示されます。
つまり、console.log
を呼び出した時点の値ではなく、ブラウザで展開した時の値を出力しているということになります。
回避策
回避策についてもMDNのドキュメントに記載がありました。
console.log(obj) を使わず、 console.log(JSON.parse(JSON.stringify(obj))) を使用してください。
これにより、ログを記録した瞬間の obj の値を確実に見ることができます。こうしないと、多くのブラウザーでは値が変化したときに常に更新されるライブビューになります。これは望むことではないかもしれません。
それでは、MDNのドキュメント通りにmain.js
を書き換えてみましょう。
(赤色の部分を削除し、代わりに緑色の部分で挿入します。)
'use strict';
class Name {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
class Human {
constructor(name, age, address1, address2) {
this.name = name;
this.age = age;
}
}
const name = new Name('太郎', '佐藤');
const human = new Human(name, 25);
- console.log(human); // firstName が 太郎, lastName が 佐藤, age が 25 と出力して欲しい
+ console.log(JSON.parse(JSON.stringify(human)));
human.name = new Name('次郎', '鈴木');;
human.age = 30;
- console.log(human); // firstName が 次郎, lastName が 鈴木, age が 30 と出力して欲しい
+ console.log(JSON.parse(JSON.stringify(human)));
main.js
を書き換えた後に、再度ブラウザで開いてみます。
期待通りの出力結果になりましたね。
まとめ
参照型データをconsole.log
で出力する時は、console.log(JSON.parse(JSON.stringify(obj)))
を使うと期待通りの出力結果が得られます。