
プログラマーとして、例え孫悟空の72の変化を持っていても、観音様の金の輪から逃れることはできません。プログラムにBugが出るのは日常茶飯事ですが、問題を解決する能力こそが、会社におけるあなたの立場を際立たせます。この記事では、自身の実戦経験に基づき、日常開発における神レベルのデバッグテクニックをまとめました。皆様の参考になれば幸いです。おかしな点がありましたら、ご指摘いただければ幸いです。
著者紹介
こんにちは、河畔一角です。ベテランフロントエンドエンジニアです。普段は仕事が忙しく、記事の投稿頻度は高くありませんが、今回のまとめが皆様のお役に立てればと思っています。
フロントエンド初心者
私はこれまで多くのコースを制作し、学生グループも十数個運営しています。多くの学生が問題に直面すると、すぐにグループで私をメンションしてきます。「ページが表示されない、見てください」「コードは同じなのに動かない」「コンソールにエラーが出る、どうすれば?」「どうやってブレークポイントを貼るの?」「どうやってデバッグすればいい?」
正直なところ、とても困りますが、彼らの気持ちはよくわかります。卒業したばかりで、真っ白な状態、実務経験もなく、業界に対する認知も低い段階にあります。そのため、問題に直面した時は、問題を一緒に調査する一方で、自分で問題を解決する能力と方法を徐々に身につけられるように手助けしたいと思っています。
フロントエンド初心者(初級)
console 大法
これはおなじみですね。問題が発生したら、console を使ってログを出力し、問題を分析します。
- console.log()
通常のログ出力で、フロントエンドが最も頻繁に使用するプリント方法です。
function Person() {
this.name = "jack";
this.age = 30;
}
let person = new Person();
// personオブジェクトのプロパティとメソッドを確認
console.log(person);
// 名前と年齢を同時に表示
console.log(person.name, person.age);
// プレースホルダを使って出力することもできます
console.log("名前:%s、年齢:%d", person.name, person.age);
出力結果:

テンプレートリテラルの方がプレースホルダより簡単ですが、ここでは詳しく説明しません。
- console.warn()
コンソールに警告情報を出力するために使用します。console.log と同じ使い方ですが、表示スタイルが異なり、warn メソッドで出力すると、前に黄色の警告マークが表示されます。
出力結果:

- console.info()
コンソールに説明情報を出力するために使用します。console.log と同じ使い方で、スタイルも同じです。
出力結果:

- console.error()
コンソールにエラー情報を出力するために使用します。console.log と同じ使い方ですが、表示スタイルが異なり、error メソッドで出力すると、前にエラーアイコンが表示されます。
出力結果:

- console.time()
コードの実行時間を取得したい場合は、console.time() で計測を開始し、console.timeEnd() で計測を終了します。
// 計測開始
console.time();
for (let i = 0; i < 1000; i++) {
// to-do
}
// 計測終了
console.timeEnd();
出力結果:

注意:
console.timeEnd()は単独では使えません。事前にconsole.time()を定義する必要があります。定義しないと、VM578:1 Timer 'default' does not existというエラーが表示されます。
- console.count()
コードの実行回数を取得したい場合は、console.count() を使用します。
for (let i = 0; i < 5; i++) {
// 回数カウント
console.count();
}
出力結果:

引数を渡してラベルを付けることもできます。例:
console.count('回数:')
以上が、console を使ったデバッグでよく使われる方法です。他にもありますが、あまり使われないものや低頻度のものは省略します。
debugger
console ログ出力の他によく使われるのが debugger です。プログラムがエラーになったり、問題が特定できない場合に、コード内に直接 debugger を記述してプログラムの実行を一時停止し、問題を分析します。
let list = [{ name:'jack' , age: 30 , info:{ score: 70} },{ name:'tom' , age: 28 }]
for (let item of list) {
debugger;
if (item.info.score > 60) {
console.log(`おめでとうございます:${item.name}`);
}
}
このコードは明らかにエラーになります。プログラムがもっと複雑な場合は、ブレークポイントデバッグが必要です。debugger を使うことで、item.info が null であるためにエラーが発生していることをデバッグで確認できます。
デバッグの様子:

Chrome ブレークポイント
コード内に console.log や debugger を書くのは、いずれも侵入型のブレークポイントです。問題解決後には手動で削除する必要があります。しかし、ブラウザ自体でもブレークポイントを貼ることができることをご存知ですか?
Vue3 を例に挙げます。コンソールを開き、ソース(Sources)タブで Ctrl + P を押してユーザー管理メニューファイル User.vue を検索し、ブレークポイントを貼りたい行をクリックするだけです。

もしブレークポイントをたくさん貼ってしまった場合、どうやって素早く解除するのでしょうか?

ブレークポイントで停止した後、変数にマウスを合わせると値が表示され、オブジェクトにマウスを合わせるとそのプロパティやメソッドが表示されます。右側のパネルには、ウォッチ式、ブレークポイント、スコープ、コールスタックなどのセクションがあります。

Chrome 条件付きブレークポイント
ループ処理をデバッグする場合、条件が成立するまで1つずつ実行しなければならないことがあります。これは非常に時間がかかり、賢い方法とは言えません。
- デバッグしたいコードを見つけます

- 右クリックして条件付きブレークポイントを選択します

userId == 1000002のときにブレークポイントをトリガーするよう設定

- 条件が成立した場合のみブレークポイントがトリガーされます

条件付きブレークポイントは本当に便利で、大絶賛です

フロントエンド上級者
リクエストの再送信
バックエンドとインターフェースのデバッグを行う際、ページからのリクエストが速すぎてバックエンドがログを確認できないことがあります。その場合、バックエンドから「リクエストをもう一度送ってください。デバッグします」と言われることがあります。そこで私たちは素直にページをリロードしてしまいますが、ブラウザ自体にリクエスト再送信機能があることをご存知ですか?
手順:
- コンソールを開く
- Network(ネットワーク)タブを選択
- 再送信したいインターフェースを見つける
- 右クリックして
Replay XHR(XHR を再送信)を選択
すると、リクエストがもう一度送信されるという驚きの光景が...
リクエスト再送信前:

リクエスト再送信後:

コンソールからリクエストを送信
リクエスト再送信時にパラメータを変更する必要がある場合はどうすればいいでしょうか?
- コンソールを開く
- Network(ネットワーク)タブを選択
- パラメータを変更したいインターフェースを見つける
- 右クリックして
Copy→Copy as fetch(fetch 形式でコピー)を選択 - コンソール画面にペースト
- リクエストパラメータを変更し、Enter キーを押す
- リクエストをコピー

- ページネーションパラメータを2ページ目に変更:

- Enter キーでリクエスト送信

HTML ノードのコピー
ページレイアウトに問題が生じた場合、要素を調査して分析し、同時にコンソールで DOM API を使って読み書きデバッグを行うことがよくあります。しかし、DOM API での操作は面倒です。実はブラウザがすでに $0 変数機能を備えていることをご存知ですか?
- 確認したい
htmlノードを選択すると、自動的に$0変数が生成されます

- コンソールで
$0と入力すると、選択したノードが表示されます

$や$$でdocument.querySelector()の代わりになります

これは本当に便利です。もしこれを知らなければ、本当に
outです。Chromeはフロントエンドのことをよく理解していますね。
JavaScript オブジェクトのコピー
console.log で複雑なオブジェクトを表示したとき、何層も展開して確認するのは非常に不便です。何か良い方法はないでしょうか?
function Person() {
this.name = "jack";
this.age = 30;
}
let person = new Person();
// person オブジェクトのプロパティとメソッドを確認
console.log(person);
ブラウザには copy 関数が組み込まれています。
copy(person)と入力

- そのまま貼り付け
コンソールはオブジェクトをフォーマットして表示します。何層も展開する必要がなく、非常に便利です。
他にも便利な変数があります:
$// 簡単に言うとdocument.querySelectorです。$$// 簡単に言うとdocument.querySelectorAllです。$_// 直前の式の値$0-$4// Elements パネルで選択された直近5つの DOM 要素です。後で説明します。dir// 実はconsole.dirです。keys// オブジェクトのキー名を取得し、キー名の配列を返します。values// オブジェクトの値を取得し、値の配列を返します。
ローカルファイルでリモートを上書き
かつてこんな状況に遭遇しました。プロジェクトがサーバーにデプロイされているが、ローカルにリポジトリのコードがなく、サーバー上のコードはすべて圧縮されているため、デバッグが非常に困難でした。通常の方法は、サーバーから圧縮パッケージをダウンロードし、ローカルで nginx を使って実行し、ローカルデバッグを行い、最後に圧縮パッケージを修正して再度サーバーにデプロイするというものでした。しかし、ブラウザには既に overrides 機能が備わっていることをご存知ですか?
コンソールを開く
ソース(Sources)タブを選択し、上書き(Overrides)をクリック

+をクリックしてフォルダを選択(デスクトップに適当なフォルダを作成してもOK)許可をクリック

ページをリロード
Network(ネットワーク)タブを選択し、変更したいファイル(
cssまたはjs)を右クリックし、「保存して上書き(Save for overrides)」を選択

- このとき、リモートファイルがローカルの対応するフォルダにダウンロードされたことが確認できます

- ファイル内でコードを直接修正すると、ページに同期して反映されます

修正後、そのまま保存
ローカルファイルを再度リモートサーバーにデプロイすれば完了です。
以上が今回お届けする様々なデバッグ機能です。お気に召しましたら幸いです。私は 河畔一角 でした。