数列の和を求めるプログラムを作成することになり、意気揚々と以下のようなプログラムを書いたという状況を想像して下さい。
function sum(nums, acc = 0) { if (nums.length === 0) return 0; if (nums.length === 1) return nums[0]; return sum(nums.slice(1), acc + nums[0]); } const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; console.log(sum(nums)); // expected: 55
一見すると何も問題なさそうに見えるプログラムですが、実はバグがあります (皆さん分かりますか?) *1。実際に上記プログラムを実行すると 55
ではなく 10
が出力されます。
こうした場面に遭遇すると、自然と sum
関数が呼び出される度に nums
と acc
がどう変化していくかを知りたくなってきます。この時取りうるデバッグ方法には様々なものがありますが、最も簡単なのは print
デバッグでしょう。
function sum(nums, acc = 0) { console.log(nums); console.log(acc); if (nums.length === 0) return 0; if (nums.length === 1) return nums[0]; return sum(nums.slice(1), acc + nums[0]); }
これを Chrome devtools の Console パネルで実行すると以下のように出力されます。出力がどう整形 (色が付いたり、クリックで折りたたみを展開できたり) されるかは、その JavaScript 実行環境 (Chrome や Firefox、Node.js など) によりますが、大体どの実行環境でも似たような見た目で出力されるはずです。
複数行に渡る出力を1行にまとめたい
実は console.log
は複数の引数を渡せるようになっていて、以下のように書くこともできます。一度に複数の値を渡すと、それらの値は一緒の行にまとめられて出力されるので、1回の呼び出しで複数行出力されて見にくいという不満を解消できます。便利ですね。
function sum(nums, acc = 0) { console.log(nums, acc); if (nums.length === 0) return 0; if (nums.length === 1) return nums[0]; return sum(nums.slice(1), acc + nums[0]); }
ここまではよくある tips ですね。
変数名も出力したい
出力する変数がだんだん増えてくると、出力の何番目がどの変数だったのか判断が難しくなります。当然変数名も一緒に出力して、どの値がどの変数のものかがひと目で分かるようにしたくなってくると思います。
そうした状況でオススメなのが、次のテクニックです。
function sum(nums, acc = 0) { console.log({ nums, acc }); if (nums.length === 0) return 0; if (nums.length === 1) return nums[0]; return sum(nums.slice(1), acc + nums[0]); }
console.log
の引数リストを { ... }
で囲うだけです。これだけで変数名も一緒に出力されるようになります。簡単ですね。
変数名が出力される仕組み
「何でこれで変数名が出力されるの?」という疑問を持った方も居るともうので、軽く解説します。先程のコードは Shorthand property names という、オブジェクトを初期化するためのシュガーシンタックスです。ES2015 で導入された比較的新しい *2 記法です。以下の2つのコードは等価になります。
console.log({ nums, acc }); console.log({ nums: nums, acc: acc, });
つまり先程のコードは、変数 nums
の値を nums
という名のプロパティに、変数 acc
の値を acc
という名のプロパティに持つオブジェクトを console.log
で出力していた訳ですね。変数名を出力していたというよりは、たまたま変数名と同じ名前のプロパティ名が出力されていて、変数名が出力されているように見えていた、という感じです。
別解: degugger;
を仕込む
結構忘れられがちなのですが、専用のデバッガを使うという手もあります。変数名の表示はもちろん、スタックトレースの表示やステップ実行ができたりと、print
デバッグよりもずっと高級なデバッグ体験が得られます。もし高級なデバッグ体験が欲しければこちらを使うのが良いでしょう。
デバッガを利用する最も手軽な方法は、 debugger
文です。変数の値を覗き見したい行に debugger;
と書いて Chrome などで実行すると、その行に到達した瞬間にデバッガが自動で起動して、実行が一時停止します *3。後はデバッガのメニューから変数の状態を見たり、ステップ実行してみたりと好き放題できます。
デバッガは利用するための環境構築が大変なイメージがあり、敬遠されがちですが、便利なのでスキを見て使っていけると良いと思っています。最近の VSCode でもエディタ組み込みのデバッガの開発に力を入れていたりと、どんどんデバッガの利用が容易になっているように感じています。debugger;
くらいなら簡単に始められるので、是非使ってみてはいかがでしょうか。
おまけ1
実行環境がChrome devtools、かつ関数呼び出しの入力を監視したい時限定で、変数名を出力出来るわけではないけど、monitor
関数も便利だよと教えて頂いた。便利!!!
おまけ2
サムネオチして完成したhttps://t.co/UnVzYgofTF
— mizdra (@mizdra) 2021年5月2日
サムネオチって言葉久々に聞いた気がする。