読み込み中...

JavaScriptで現在のファイルパスと行番号を取得する12の手法

JavaScriptでファイルパスと行番号を取得する方法 JS
この記事は約19分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

●JavaScriptで行番号を取得する方法とは?

JavaScriptを使ってWebアプリケーションを開発していると、デバッグやエラー処理のために現在のファイルパスや行番号を取得したいと思うことがありますよね。

特に、実務経験が比較的浅いエンジニアの方は、この課題にぶつかることが多いのではないでしょうか。

ただ、JavaScriptには、ファイルパスや行番号を取得するための様々な手法があります。

この手法を身につけることで、デバッグ作業を効率化し、生産性を上げることができるでしょう。

本記事では、JavaScriptでファイルパスと行番号を取得する代表的な方法を、サンプルコードを交えて詳しく解説していきます。

記事を読み進めることで、ファイルパスや行番号の取得方法を体系的に理解し、自分のスキルアップにつなげることができるはずです。

それでは、具体的な手法を見ていきましょう。

○Error.stackを使った行番号の取得

Error.stackを使うと、エラーが発生した位置の情報を取得できます。この情報には、ファイルパスや行番号が含まれています。

○サンプルコード1:Error.stackの基本的な使い方

function getLineNumber() {
  try {
    throw new Error();
  } catch (error) {
    const stackLines = error.stack.split('\n');
    const callerLine = stackLines[1];
    const lineNumber = callerLine.match(/:(\d+):\d+$/)[1];
    return lineNumber;
  }
}

console.log('現在の行番号:', getLineNumber());

このコードでは、次のようなステップで行番号を取得しています。

  1. tryブロック内で意図的にエラーを発生させる
  2. catchブロックでエラーオブジェクトを取得する
  3. error.stackからスタックトレースを取得し、改行で分割する
  4. 分割したスタックトレースの2行目(呼び出し元の情報)を取得する
  5. 正規表現を使って行番号を抽出する

実行すると、次のように現在の行番号が出力されます。

現在の行番号: 11

Error.stackを使った行番号の取得は、シンプルでわかりやすい手法です。

ただ、ブラウザによってはスタックトレースの形式が異なる場合があるので、クロスブラウザ対応には注意が必要ですね。

●window.onerrorを使った行番号の取得

次に紹介するのは、window.onerrorを使った行番号の取得方法です。

window.onerrorは、JavaScriptのエラーが発生した際に呼び出されるグローバルイベントハンドラです。

このイベントハンドラを利用することで、エラー情報を取得し、ファイルパスや行番号を特定することができます。

○サンプルコード2:window.onerrorでエラー情報を取得

window.onerror = function(message, source, lineno, colno, error) {
  console.log('エラーメッセージ:', message);
  console.log('ファイルパス:', source);
  console.log('行番号:', lineno);
  console.log('列番号:', colno);
  console.log('エラーオブジェクト:', error);
};

// 意図的にエラーを発生させる
nonExistentFunction();

このコードでは、window.onerrorイベントハンドラを定義しています。

イベントハンドラには、次の引数が渡されます。

  • message:エラーメッセージ
  • source:エラーが発生したファイルのURL
  • lineno:エラーが発生した行番号
  • colno:エラーが発生した列番号
  • error:エラーオブジェクト

実行すると、次のようなエラー情報が出力されます。

エラーメッセージ: Uncaught ReferenceError: nonExistentFunction is not defined
ファイルパス: http://example.com/script.js
行番号: 10
列番号: 1
エラーオブジェクト: ReferenceError: nonExistentFunction is not defined
    at http://example.com/script.js:10:1

window.onerrorを使えば、エラーが発生した際のファイルパスや行番号を簡単に取得できます。

ただし、このイベントハンドラはエラーが発生した後に呼び出されるため、エラーを事前に防ぐことはできません。

エラーハンドリングと併用して使うのがおすすめですね。

○サンプルコード3:window.onerrorの応用例

window.onerror = function(message, source, lineno, colno, error) {
  const errorInfo = {
    message: message,
    source: source,
    lineno: lineno,
    colno: colno,
    error: error
  };

  // エラー情報をサーバーに送信
  sendErrorToServer(errorInfo);

  // ユーザーにエラーメッセージを表示
  displayErrorMessage(message);

  // デフォルトのエラー処理を無効化
  return true;
};

function sendErrorToServer(errorInfo) {
  // XMLHttpRequestなどを使ってエラー情報をサーバーに送信する
  // ...
}

function displayErrorMessage(message) {
  // エラーメッセージをユーザーに表示する
  // ...
}

// 意図的にエラーを発生させる
nonExistentFunction();

このコードでは、window.onerrorイベントハンドラ内で次のような処理を行っています。

  1. エラー情報をオブジェクトにまとめる
  2. エラー情報をサーバーに送信する
  3. ユーザーにエラーメッセージを表示する
  4. デフォルトのエラー処理を無効化する

window.onerrorを応用することで、エラー情報の収集やユーザーへのフィードバックなど、様々な用途に活用できます。

○サンプルコード4:window.onerrorのクロスブラウザ対応

window.onerror = function(message, source, lineno, colno, error) {
  // Internet Explorerの場合、引数の数が異なる
  if (typeof colno === 'undefined') {
    colno = window.event && window.event.errorCharacter || 0;
  }

  // エラー情報を処理する
  // ...

  // デフォルトのエラー処理を無効化
  return true;
};

window.onerrorはブラウザによって引数の数や順番が異なる場合があります。

特に、Internet Explorerではcolno引数がサポートされていません。

クロスブラウザ対応をする際は、引数の存在チェックや代替手段の使用など、ブラウザの違いを考慮する必要があります。

●console.traceを使った行番号の取得

JavaScriptでファイルパスや行番号を取得する方法として、console.traceを使う方法もあります。

console.traceは、現在の実行位置からコールスタックのトレースを出力するための関数です。

このトレース情報には、各関数呼び出しのファイルパスと行番号が含まれているので、デバッグやエラー処理に役立ちます。

実際に、console.traceを使ってみましょう。

○サンプルコード5:console.traceでスタックトレースを表示

function foo() {
  console.trace('トレースポイント');
}

function bar() {
  foo();
}

function baz() {
  bar();
}

baz();

このコードでは、foo関数内でconsole.traceを呼び出しています。

実行すると、次のようなスタックトレースが出力されます。

トレースポイント
    at foo (http://example.com/script.js:2:11)
    at bar (http://example.com/script.js:6:3)
    at baz (http://example.com/script.js:10:3)
    at http://example.com/script.js:13:1

トレース情報には、各関数呼び出しのファイルパスと行番号が含まれています。

これにより、コードのどの部分が実行されているかを把握することができます。

ただし、console.traceはデバッグ用の関数なので、製品コードに残しておくのは避けた方が良いでしょう。

デバッグ時にのみ使用し、不要になったら削除するようにしましょう。

○サンプルコード6:console.traceの活用方法

function getLineNumber() {
  const stack = new Error().stack;
  const trace = stack.split('\n')[2];
  const lineNumber = trace.match(/:(\d+):\d+\)?$/)[1];
  return lineNumber;
}

function foo() {
  console.log('現在の行番号:', getLineNumber());
  // ここでconsole.traceを使用する
  console.trace('トレースポイント');
}

foo();

このコードでは、getLineNumber関数を定義し、Errorオブジェクトのスタックトレースから行番号を取得しています。

foo関数内では、getLineNumberを呼び出して現在の行番号をログ出力した後、console.traceを使用しています。

実行すると、次のような結果が得られます。

現在の行番号: 10
トレースポイント
    at foo (http://example.com/script.js:11:11)
    at http://example.com/script.js:15:1

getLineNumberで取得した行番号と、console.traceのトレース情報を組み合わせることで、より詳細なデバッグ情報を得ることができます。

●ファイルパスの取得方法

ここまでは、JavaScriptで行番号を取得する方法について詳しく見てきました。

でも、実際のデバッグ作業では、行番号だけでなくファイルパスも知りたいと思うことがありますよね。

特に、複数のファイルにまたがるようなコードを扱っている場合、エラーがどのファイルで発生しているのかを特定することが重要です。

そこで、ここからはJavaScriptでファイルパスを取得する方法について解説していきます。

ファイルパスの取得には、いくつかの手法がありますが、ここではその中でもよく使われる2つの方法を紹介します。

○arguments.callee.stackを使ったファイルパスの取得

最初に紹介するのは、arguments.callee.stackを使ったファイルパスの取得方法です。

arguments.calleeは、現在実行中の関数を参照するための特殊なプロパティです。

このプロパティに付属するstackプロパティには、関数呼び出しのスタックトレースが格納されています。

それでは、実際にarguments.callee.stackを使ってファイルパスを取得してみましょう。

○サンプルコード7:arguments.callee.stackの使用例

function getFilePath() {
  const stack = arguments.callee.caller.toString();
  const filePathRegex = /at\s(.+):\d+:\d+/;
  const match = stack.match(filePathRegex);
  return match ? match[1] : '';
}

function foo() {
  console.log('現在のファイルパス:', getFilePath());
}

foo();

このコードでは、getFilePath関数を定義し、arguments.callee.callerを使って呼び出し元の関数のスタックトレースを取得しています。

そして、正規表現を使ってファイルパスを抽出し、戻り値として返しています。

foo関数内でgetFilePathを呼び出すと、次のようにファイルパスが出力されます。

現在のファイルパス: http://example.com/script.js

arguments.callee.stackを使えば、比較的簡単にファイルパスを取得できます。

ただし、この方法には注意点もあります。

まず、arguments.calleeはECMAScript 5以降では非推奨となっており、strict modeでは使用できません。

また、ブラウザによってはスタックトレースの形式が異なることがあるので、クロスブラウザ対応には工夫が必要です。

とはいえ、ファイルパスの取得方法の1つとして覚えておくと便利だと思います。

デバッグ時にさっと使えるようにしておくのがおすすめです。

●__stack__プロパティを使ったファイルパスの取得

JavaScriptでファイルパスを取得するもう1つの方法は、__stack__プロパティを使う方法です。

__stack__は、Firefoxでサポートされている非標準のプロパティで、関数呼び出しのスタックトレースを文字列として提供します。

__stack__プロパティを使えば、比較的簡単にファイルパスを取得できます。

早速、具体的な使用例を見てみましょう。

○サンプルコード8:stackプロパティの利用方法

function getFilePath() {
  const stack = new Error().stack;
  const stackLines = stack.split('\n');
  const callerLine = stackLines[1];
  const filePathRegex = /at\s(.+):\d+:\d+/;
  const match = callerLine.match(filePathRegex);
  return match ? match[1] : '';
}

function foo() {
  console.log('現在のファイルパス:', getFilePath());
}

foo();

このコードでは、次のようなステップでファイルパスを取得しています。

  1. Errorオブジェクトを生成し、その__stack__プロパティからスタックトレースを取得する
  2. スタックトレースを改行で分割し、配列に格納する
  3. 配列の2番目の要素(呼び出し元の情報)を取得する
  4. 正規表現を使ってファイルパスを抽出する

実行すると、次のようにファイルパスが出力されます。

現在のファイルパス: http://example.com/script.js

__stack__プロパティを使う方法は、比較的新しいブラウザでサポートされているので、モダンなWebアプリケーション開発では使いやすいと思います。

○サンプルコード9:__stack__プロパティの注意点

function getFilePath() {
  if (!new Error().stack) {
    console.warn('__stack__プロパティがサポートされていません');
    return '';
  }

  const stack = new Error().stack;
  const stackLines = stack.split('\n');
  const callerLine = stackLines[1];
  const filePathRegex = /at\s(.+):\d+:\d+/;
  const match = callerLine.match(filePathRegex);
  return match ? match[1] : '';
}

function foo() {
  console.log('現在のファイルパス:', getFilePath());
}

foo();

ただし、__stack__プロパティはFirefoxでしかサポートされていないので、他のブラウザでは使えません。

したがって、クロスブラウザ対応が必要な場合は、__stack__プロパティの存在チェックを行う必要があります。

サンプルコード9では、__stack__プロパティの存在チェックを追加しています。

__stack__プロパティがサポートされていない場合は、警告メッセージをコンソールに出力するようにしています。

●よくあるエラーと対処法

JavaScriptでファイルパスや行番号を取得する際に、よくぶつかるエラーがあります。

せっかく頑張ってコードを書いても、思うような結果が得られないと焦ってしまいますよね。

ここでは、そんなエラーへの対処法を何点か紹介します。

これらの対処法を知っておけば、エラーに出くわしてもあわてることなく、冷静に問題を解決できるはずです。

それでは、具体的に見ていきましょう。

○スタックトレースが取得できない場合の対処法

スタックトレースが取得できない場合、次のような原因が考えられます。

  • ブラウザがスタックトレースをサポートしていない
  • 呼び出し元の関数がない(グローバルスコープで実行された)
  • 関数が名前付き関数式になっている

これらの場合、スタックトレースが空になったり、期待したような情報が得られなかったりします。

対処法としては、次のようなことが挙げられます。

  • 可能な限り、スタックトレースをサポートしているブラウザを使う
  • 呼び出し元の関数を用意する
  • 関数宣言や無名関数を使う

ただし、根本的な解決には至らない場合もあるので、状況に応じて柔軟に対応することが大切ですね。

○ファイルパスや行番号が正しく取得できない場合の対処法

ファイルパスや行番号が正しく取得できない場合、次のような原因が考えられます。

  • ブラウザによってスタックトレースの形式が異なる
  • minifyされたコードを使用している
  • eval()やnew Function()でコードを実行している

これらの場合、期待したファイルパスや行番号とは異なる結果が返ってくることがあります。

対処法としては、次のようなことが挙げられます。

  • ブラウザごとにスタックトレースのパースを調整する
  • ソースマップを使ってminifyされたコードとオリジナルのコードを紐付ける
  • eval()やnew Function()の使用を避ける

特に、本番環境ではminifyされたコードを使うことが多いので、ソースマップを活用するのが効果的だと思います。

○パフォーマンスへの影響と対策

ファイルパスや行番号を取得する処理は、一般的にパフォーマンスへの影響は小さいです。

しかし、大量のエラーが発生した場合や、頻繁に呼び出される関数内で使用した場合は、パフォーマンスが低下する可能性があります。

パフォーマンスを向上させるためには、次のような対策が考えられます。

  • エラーが発生しないようにコードを修正する
  • 必要な時だけファイルパスや行番号を取得する
  • 取得した情報をキャッシュして再利用する

例えば、エラーが発生するたびにファイルパスや行番号を取得するのではなく、一定時間ごとにまとめて取得するようにすれば、パフォーマンスの低下を防げるでしょう。

●ファイルパスと行番号の取得の応用例

さて、ここまでJavaScriptでファイルパスや行番号を取得する様々な方法を見てきましたが、実際のアプリケーション開発では、これらの情報をどのように活用するのでしょうか?

ここからは、ファイルパスと行番号の取得を応用した具体的な例を紹介していきます。

この例を参考にして、自分のプロジェクトでデバッグやエラー処理の効率化を図ってみてください。

○サンプルコード10:Errorオブジェクトの文字列変換を利用

最初の例は、Errorオブジェクトの文字列変換を利用したものです。

Errorオブジェクトをそのまま文字列に変換すると、スタックトレースを含む詳細なエラー情報が得られます。

function foo() {
  try {
    throw new Error('エラーが発生しました');
  } catch (error) {
    console.log(error.toString());
  }
}

foo();

このコードを実行すると、次のようなエラー情報が出力されます。

Error: エラーが発生しました
    at foo (http://example.com/script.js:3:11)
    at http://example.com/script.js:8:1

エラーメッセージに加えて、エラーが発生した関数名、ファイルパス、行番号などが含まれています。

この情報を利用して、エラーログをわかりやすく整形したり、エラー発生箇所を特定したりできます。

○サンプルコード11:sourcemap-supportでソースマップを利用

次の例は、sourcemap-supportを使ってソースマップを利用するものです。

ソースマップとは、minifyされたコードとオリジナルのコードを紐付けるためのファイルです。

const sourceMapSupport = require('source-map-support');
sourceMapSupport.install();

function foo() {
  throw new Error('エラーが発生しました');
}

foo();

このコードでは、source-map-supportモジュールをインストールし、ソースマップのサポートを有効化しています。

エラーが発生すると、minifyされたコードの位置ではなく、オリジナルのコードの位置が表示されます。

実行結果は次のようになります。

Error: エラーが発生しました
    at foo (original.js:5:9)
    at Object.<anonymous> (original.js:8:1)

ソースマップを利用することで、デバッグ時にオリジナルのコードの位置を参照できるため、とても便利です。

特に、本番環境でminifyされたコードを使用している場合に効果を発揮します。

○サンプルコード12:Node.jsでファイルパスを取得

最後の例は、Node.js環境でファイルパスを取得するものです。

Node.jsでは、モジュールシステムを使ってファイルを管理しています。

function foo() {
  console.log('現在のファイルパス:', __filename);
}

foo();

このコードでは、__filenameという特殊な変数を使って、現在のファイルのフルパスを取得しています。

実行すると、次のようにファイルパスが出力されます。

現在のファイルパス: /path/to/script.js

Node.jsでファイル関連の処理を行う際には、__filename__dirname(現在のディレクトリのパス)を活用すると便利です。

まとめ

はい、JavaScriptでファイルパスと行番号を取得する方法について、詳しく見てきました。

Error.stackやwindow.onerror、console.traceなど、様々な手法があることがわかりましたね。

冒頭でお話ししたように、JavaScriptでのデバッグやエラー処理は、エンジニアにとって重要なスキルです。

本記事で紹介した手法を身につければ、ファイルパスや行番号を的確に取得し、デバッグやエラー処理の問題解決力を高めることができるはずです。

サンプルコードを参考に、自分のプロジェクトで積極的に活用してみてください。