「翻訳」公式ガイドシリーズ:JavaScriptデバッグガイド(一)

✍🏼 作成日 2022年09月13日    💡 更新日 2022年09月13日
❗️ 注意:この記事が作成されてから既に 日が経過しています。情報の鮮度にご注意ください
🖥  説明:公式ガイドシリーズその1
📚  Craft にも公開: https://www.craft.do/s/kyKcQKCEQjAksv

この包括的なChrome DevToolsデバッグ機能の紹介が、あなたのデバッグプロセスをさらに向上させることを願っています。

まず最初に、基本的なデバッグテクニックをこちら(英語、翻訳待ち)で学ぶ必要があるかもしれません。

ブレークポイントでコードを一時停止する

ブレークポイントを設定することで、コードの実行途中で一時停止させることができます。

ブレークポイントの設定方法についてはこちら(英語、翻訳待ち)を参照してください。

マウスホバー時にクラス/関数のプロパティを確認する

コードの実行が一時停止している状態で、クラスや関数名にマウスをホバーさせると、そのプロパティをプレビューできます。

1

コードをステップ実行する

コードが一時停止した後、1行ずつコードを実行することで、呼び出しスタックや関連するプロパティの値を確認できます。

現在のコード行をスキップ(Step over)

調査中の問題に関係ないコード行で、その行に関数が含まれている場合、Step Overをクリックするとその関数の中に入らずにコードの実行を続行できます。

step_over

図1 👆🏻、上の画像の青い枠内にある Step Over の意味を説明します:

例として、以下のコードをデバッグしていると仮定します:

1
2
3
4
5
6
7
8
9
function updateHeader() {
var day = new Date().getDay();
var name = getName(); // A
updateName(name); // D
}
function getName() {
var name = app.first + ' ' + app.last; // B
return name; // C
}

この時、ブレークポイントは A の位置で停止しています。Step over をクリックすると、Devtools は「Step over」した位置にあるすべてのコードを実行します。上記の例では、「Step over」したのは A の位置にある getName 関数内の BC の位置です。そのため、Devtools はコードを D の位置で停止させます。

現在のコード行に入る(Step into)

ブレークポイントが調査対象の問題に関連する場所で停止しており、その場所に関数呼び出しが含まれている場合、Step into をクリックすることで、その関数をさらに詳しく検査できます。

step_into

図2 👆🏻、上の図の青い枠内にある Step into の意味の説明:

例として、以下のコードをデバッグしていると仮定します:

1
2
3
4
5
6
7
8
9
function updateHeader() {
var day = new Date().getDay();
var name = getName(); // A
updateName(name);
}
function getName() {
var name = app.first + ' ' + app.last; // B
return name;
}

ブレークポイントが A の位置で停止している場合、Step into をクリックすると、Devtools はこの行のコードを実行し、B の位置で停止します。

現在のコード行から抜け出す(Step out)

調査中の問題に関連しない関数内部でブレークポイントが停止している場合、Step out をクリックすると、その関数内の残りのコードを実行して抜け出します。

step_out

図3 👆🏻、上の図の青い枠内にある Step out の意味を説明します:

例として、以下のコードをデバッグしていると仮定します:

1
2
3
4
5
6
7
8
9
function updateHeader() {
var day = new Date().getDay();
var name = getName();
updateName(name); // C
}
function getName() {
var name = app.first + ' ' + app.last; // A
return name; // B
}

現在、ブレークポイントは A の位置で停止しています。この状態で Step out をクリックすると、DevTools は getName() 関数内の残りのコード(つまり位置 B のコード)を実行し終えた後、ブレークポイントを位置 C で停止させます。

指定行までコードを継続実行

長い関数をデバッグしている場合、調査中の問題に関係のないコードが多く含まれていることがあります。

これらの無関係な行を1つずつステップ実行することもできますが、このプロセスは退屈です。また、ブレークポイントを設定したいコード行にブレークポイントを設定し、Resume Script Execution(スクリプト実行を再開)を押すこともできますが、さらに速い方法があります。

ブレークポイントを設定したいコード行を右クリックし、Continue to here(ここまで実行)を選択できます。DevTools はブレークポイントを再開し、その行までコードを実行した後、その行で停止します。

continue_to_here

図4 👆🏻 で Continue to here を選択します。

スクリプト実行の再開

Resume Script Execution をクリックすることで、ブレークポイントで一時停止した位置からコードの実行を再開できます。Devtools は次のブレークポイント(存在する場合)に達するまでコードを実行し続けます。

resume_script_execution

図5 👆🏻、Resume Script Execution 、青枠部分。

強制実行

Resume Script Execution を長押しし、Force Script Execution を選択することで、残りのすべてのブレークポイントを無視し、コード全体を直接実行できます。

force_script_execution

図六 👆🏻 で Force Script Execution を選択します。

現在のスレッドのコンテキストを変更する

デバッグが Web Worker または Service Worker に関連する場合、Threads バーに表示されるコンテキストリスト項目をクリックすることで、コンテキストを切り替えることができます。青い矢印は現在選択されているコンテキストを示しています。

change_threads_context

図7 👆🏻のThreads(スレッド)欄、青枠の位置を参照してください。

例として、次のようなシナリオを考えます。ブレークポイントがメインスクリプトとservice workerスクリプトの両方に存在する場合です。service worker内のローカル変数とグローバル変数を確認したいが、Source欄には現在メインスクリプトのコンテキストが表示されているとします。この時、Threads欄のservice workerエントリをクリックすることで、コンテキストを切り替えて目的の変数を確認できます。

ローカルスコープ、クロージャ、グローバルスコープの変数/プロパティを表示・編集する

特定の行で実行を一時停止している間、Scope欄を使用してローカル、クロージャ、グローバル変数を表示および編集できます。

  • プロパティ値をダブルクリックして変更します。

  • 列挙不可のプロパティは灰色で強調表示されます。

查看和修改变量

図八 👆🏻、Scope(スコープ)欄の青枠の位置。

現在のコールスタックを確認する

コードの特定の行で停止している場合、Call Stack 欄を使用して、コード実行から現在の停止ポイントまでの関数コールスタックを確認できます。

コードに非同期コードが含まれている場合は、Async チェックボックスをオンにして非同期関数コールスタックを有効にできます。

エントリのいずれかをクリックすると、そのエントリが示す関数の呼び出し元にジャンプします。青色の矢印アイコンは、現在ハイライト表示されている関数を示しています。

查看函数调用栈

図九 👆🏻、Call Stack(コールスタック)欄の青枠の位置。

注意:コードが特定の行で停止していない場合、Call Stack欄は空になります。

スタック内の関数を再実行する

特定の関数の動作を確認したいが、デバッグプロセス全体を再実行したくない場合があります。そのような場合、関数内でブレークポイントが停止している間に、その関数だけを個別に再実行できます。つまり、コールスタック内に関数の呼び出しコンテキストを再配置することが可能です。

注意:WebAssembly、async、およびgenerator関数を除く、Call Stack(コールスタック)内の任意の関数を最初から再実行できます。

関数を再実行する手順:

  1. ブレークポイントを使用して関数を停止させます。Call Stack欄に関数の呼び出し順序が記録されます。

  2. Call Stack欄で、関数を右クリックし、表示されるメニューから「Restart frame」(関数を最初から実行)を選択します。

重新执行断点所在的函数

再開フレームの実行方法を理解するために、以下のコードを想定します:

1
2
3
4
5
6
7
8
9
10
11
12
function foo(value) {
console.log(value);
bar(value);
}

function bar(value) {
value++;
console.log(value);
debugger;
}

foo(0);

foo 関数は 0 を引数として受け取り、log でコンソールに出力した後、bar() 関数を呼び出します。対応して、bar 関数はこの値を1増加させます。

以下の方法でこれら2つの関数を最初から実行してみてください:

  • 上記のコードを スニペット にコピーし、実行 します。ブレークポイントは debugger が記述された コード行 で停止します。

    ⚠️ 注意:コードの実行が一時停止している間、現在のコールスタック内の関数をコンソールで実行しないでください。予期せぬエラーが発生する可能性があります。

  • 現在のデバッガーが、その関数宣言の右側に現在の値 value = 1 を表示することに気付くでしょう。

注意函数声明处右侧的值

  • bar() 関数を最初から再実行します。

重头执行bar

  • F9 を押すと、コードは値がインクリメントされる行を通過し、再度デバッガーで停止します。

    値が 2 に変わっていることに注意してください: value = 2

重头执行debugger

  • それ以外にも、Scope欄でvalueの値をダブルクリックして編集し、任意の値に設定することもできます。

双击编辑值

  • bar() 関数を複数回実行してみると、値が増加し続けることがわかります。

多次重复执行后值会一直增加

💡 驚き!なぜ value0 にリセットされないのか?

関数を最初から実行する場合、引数はリセットされません。言い換えると、最初から実行しても関数が呼び出されたときの初期状態には戻りません。したがって、これは単に呼び出しスタック内で現在の呼び出しポインタを関数の開始位置に移動するだけです。

そのため、現在の引数値 value は、同じ関数が繰り返し実行される間、メモリ内に保持され続けます。

  • ここで、Call Stack 内で foo() 関数を最初から実行します。

重头执行foo函数

注目してください、value が再び0に戻っています。

value重新变为0

💡 再び驚き!なぜ value が今回 0 にリセットされたのでしょうか?

簡単に言えば(ここでは意訳しています)、JavaScriptでは引数は値渡しです。value がプリミティブ値であるため、関数内でその値を変更しても関数外の値には影響しません。

コールスタックの実行パスをコピーする

Call Stack ペインの任意の場所で右クリックし、Copy Stack Trace(スタックトレースをコピー)を選択すると、現在のコールスタックがクリップボードにコピーされます。

复制调用栈

図十 👆🏻、Copy Stack Trace を選択します。

コピーされる内容はおおよそ以下のようになります:

1
2
3
getNumber1 (get-started.js:35)
inputsAreEmpty (get-started.js:22)
onClick (get-started.js:15)

特定のスクリプトまたは条件を満たすスクリプトを無視する

デバッグ中に特定のスクリプトを無視してスキップすることができます。これは通常、そのスクリプトの関数が複雑で理解しにくく、現在のデバッグ内容と関係がない場合に選択します。

例えば、以下のコードをデバッグしていると仮定します:

1
2
3
4
5
function animate() {
prepare();
lib.doFancyStuff(); // A
render();
}

A は信頼できるサードパーティ製ライブラリです。調査中の問題がこのサードパーティ製ライブラリに関係ないと確信できる場合、それを無視するのは賢明な判断です。

Sourceエディターバーから特定のスクリプトを無視する方法

  1. ファイルを開く

  2. 任意の場所で右クリック

  3. Add script to ignore list(スクリプトを無視リストに追加)を選択

忽略脚本

図11 👆🏻、エディターバーからスクリプトを無視する方法。

Call Stack(コールスタック)バーから特定のスクリプトを無視する

コールスタックから特定のスクリプトを無視したい場合、以下の手順を実行してください:

  1. コールスタック内の任意の関数を右クリックします。

  2. Add script to ignore list を選択します。

从调用栈中忽略脚本

図12 👆🏻、Call Stack(コールスタック)から特定のスクリプトを無視する。

Settings(設定)から特定のスクリプトを無視する

訳者注:ここでの設定はDevtoolsの設定であり、ブラウザの設定ではありません。

設定から特定のスクリプトまたは特定の条件を満たすスクリプトを無視したい場合は、以下の手順を実行してください:

  1. 設定を開く:

  2. Ignore Listタブをクリックします。

  3. Add patternをクリックします。

  4. 無視したいスクリプト名またはスクリプト名にマッチする正規表現を入力します。

  5. Addをクリックします。

devoools设置界面

devtools忽略脚本

図13 👆🏻、Settingからスクリプトを無視する。

任意のページからdebugコードSnippets(スニペット)を実行する

Consoleで繰り返し実行しているdebugコードがある場合、Snippetsの利用を検討してみてください。SnippetsはDevtoolsに保存して実行できるスクリプトです。

詳細はhttps://developer.chrome.com/docs/devtools/javascript/snippets/(未翻訳)を参照してください。

訳者注:Snippetsは実行時に現在のコンテキストを保持します。例えばdebug中に一時停止した状態でSnippetsコードを実行すると、そのSnippetsコードは現在のコンテキストの変数にアクセスできます。

Watch(監視)でカスタムJavaScript式の値を監視する

Watchバーを使用してカスタム式の値を監視します。有効なJavaScript式であれば何でも監視できます。

监听JavaScript表达式

図14 👆🏻の青い丸で囲まれた部分が「Watch」欄です。

  • 「Add Expression」(式の追加)をクリックして新しい監視式を作成します。

  • 「Refresh」(更新)をクリックして既存の式をすべて更新します。コード実行時には値が自動的に更新されます。

  • 式にマウスをホバーさせ、「Delete Expression」(式の削除)をクリックすると削除できます。

圧縮されたコードを読みやすい形式に整形

Fromat {}をクリックすると、圧縮されたコードが人間が読みやすい形式に整形されます。

格式化压缩后的文件

スクリプトの編集

バグを修正する際、JavaScriptコードの変更効果をテストする必要が頻繁にあります。外部エディタでJavaScriptコードを編集し、ページを再読み込みして効果を確認する必要はありません。Devtools内で直接JavaScriptコードを編集できます。

スクリプトを編集するには、以下の手順に従ってください:

  1. Sourceタブで編集したいファイルを開きます(Editorタブに表示されます)。

  2. Editorタブで変更を加えます。

  3. Command + S(Mac)または Ctrl + S(Windows、Linux)を押して変更を保存します。Devtoolsはパッチ形式でjsファイル全体をChromeのJavaScriptエンジンに適用します。

直接编辑js文件

上の図で青い枠で囲まれている部分がエディターバーです。

一時停止中の関数をリアルタイムで編集する

注意:この機能は Chrome 105 以降で利用可能です。

コードが一時停止しているとき、現在の関数を編集して変更をリアルタイムで適用できますが、以下の制限があります:

  • Call Stack の最上位にある関数(つまり現在のブレークポイントがある関数)のみ編集可能です。

  • コールスタック内に同じ関数への再帰呼び出しがあってはいけません(そうでないと、現在のコールスタック以外の関数も変更することになります)。

💡 一時停止中の関数をリアルタイム編集する仕組み…
変更を適用すると、デバッガーツールは自動的に関数を再実行します(前述の「コールスタック内の関数を再実行」と同じ)。したがって、再実行可能な関数に対する制限は、リアルタイム編集が有効になる制限と同一です。WebAssembly、非同期関数、ジェネレータ(イテレータ)関数を最初から再実行することはできません。

関数をリアルタイムで編集するには:

  1. ブレークポイントで一時停止します。

  2. ブレークポイントで一時停止中の現在の関数を編集します。

  3. Command/Control+S を押して変更を適用すると、デバッガーが自動的に関数を再実行します。

  4. 実行を続行します

この例では、addend1addend2 変数が最初に誤って string 型として扱われています。その結果、数値の加算ではなく文字列が連結されてしまいます。この問題を修正するために、parseInt() 関数がリアルタイム編集時に追加されました。

スクリプト内のテキストを検索・置換する

スクリプト内で特定のテキストを検索したい場合、以下の手順を実行します:

  1. コードソース(Sources)- エディター(Editor)ペインでファイルを開きます。

  2. Command+F(Mac)または Ctrl+F(Windows、Linux)を押して、組み込みの検索バーを開きます。

  3. 検索バーに、検索したい文字列を入力します:

    さらに以下の操作も可能です:

    • Aa をクリックして大文字小文字を区別し、検索を大文字小文字区別に設定します。

    • .* をクリックして正規表現を使用します。

  4. Enter キーを押して検索を実行します。上下キーで次の/前の検索結果に移動できます。

搜索字符

検索結果を置換したい場合、以下の手順を実行してください:

  1. 検索バーを開き、A→B(手書きで表現しにくいため、下図を参照)つまり置換ボタンをクリックしてテキストを置換します。

  2. 置換したいテキストを入力し、Replace または Replace all をクリックします。

按下替换按钮

JavaScriptの無効化

詳細はこちら:Disable JavaScript With Chrome DevTools(未翻訳)。

- EOF -
この記事の初出: 「翻訳」公式ガイドシリーズ:JavaScriptデバッグガイド(一) - Xheldon Blog