JavaScriptの呼び出し元関数の行番号を取得する方法は?JavaScriptの呼び出し元のURLを取得する方法は?


109

JavaScriptの呼び出し元の関数名を取得するために以下を使用しています。

var callerFunc = arguments.callee.caller.toString();
callerFuncName = (callerFunc.substring(callerFunc.indexOf("function") + 8, callerFunc.indexOf("(")) || "anoynmous")

メソッドが呼び出された行番号を見つける方法はありますか?

また、メソッドが呼び出されたJavaScriptファイルの名前を取得する方法はありますか?またはソースURL?


2
これはIEでは不可能だと思います。さもなければ、詳細を提供しないCRAPPYエラーメッセージを回避する方法があるでしょう。しかし、可能であれば私も知りたいです。
ゾイドバーグ、

はい。ここでは、各ブラウザの独自のメソッドを使用するクロスブラウザの機能です:github.com/eriwen/javascript-stacktrace [固定リンク]
スコッツ

回答:


99

これは私にとってchrome / QtWebViewで動作します

function getErrorObject(){
    try { throw Error('') } catch(err) { return err; }
}

var err = getErrorObject();
var caller_line = err.stack.split("\n")[4];
var index = caller_line.indexOf("at ");
var clean = caller_line.slice(index+2, caller_line.length);

ノードでも動作します。これをカスタムlog()関数内にポップし(これにより、必要なその他の便利な回避策が追加されます(例:Chromeアレイロギング用に修正)、log()を呼び出した場所からの行番号が残ります。
mikemaccana 2012

60
エラーをスローする必要はありません。単にそれを作成するだけでは十分である:var caller_line = (new Error).stack.split("\n")[4]
ELLIOTTCABLE

2
参照- FF / Webkitの「標準化」の応答を取得するために別の同様の答えを、この提案を吸収合併stackoverflow.com/a/14841411/1037948
drzaus

1
PhantomJSでも動作しますが、スローする必要があります。そうしないと、エラーに「スタック」属性が設定されません。
ジョシュアリチャードソン

1
@ELLIOTTCABLE実際には、iOSサファリのような一部のブラウザーでは、例外をスローする必要があります!それで、なぜそれをしないのですか?
Arctelix

26

kangaxのソリューションは、不必要なtry..catchスコープを導入します。JavaScriptで何かの行番号にアクセスする必要がある場合(FirefoxまたはOperaを使用している場合)、にアクセスします(new Error).lineNumber


11
こんにちは、そのアドオンをありがとう。以前の呼び出しから行番号を取得することが可能かどうか知っていますか?メソッドAがBを呼び出し、今BIでAの下のどの行で呼び出しが行われたかを知りたいとしましょう。
タル

85
これはチェックされていますが、呼び出し側関数の行番号を取得する方法である質問には答えません。
mikemaccana 2012

2
また、これは非常に制限されています。最善の解決策は、エラーをスローし、すべての最新のブラウザーで使用可能なerror.stackで正規表現を使用することです。そのパス、ファイル、行、列を簡単に抽出できます。問題ない。
arctelix

13

これらの回答のほとんどが、通常の場合にも役立つデバッグトレースを出力するだけでなく、エラーを処理することを想定していることに驚いていました。

たとえば、次のようなconsole.logラッパーを使用するのが好きです。

consoleLog = function(msg) {//See https://stackoverflow.com/a/27074218/470749
    var e = new Error();
    if (!e.stack)
        try {
            // IE requires the Error to actually be thrown or else the 
            // Error's 'stack' property is undefined.
            throw e;
        } catch (e) {
            if (!e.stack) {
                //return 0; // IE < 10, likely
            }
        }
    var stack = e.stack.toString().split(/\r\n|\n/);
    if (msg === '') {
        msg = '""';
    }
    console.log(msg, '          [' + stack[1] + ']');        
}

これにより、次のような出力がコンソールに出力されます。

1462567104174 [getAllPosts@http://me.com/helper.js:362:9]

https://stackoverflow.com/a/27074218/を参照してくださいまた、正しい行番号のconsole.logの適切なラッパーですか?


1
Firefoxブラウザでは機能しますが、node.jsでは機能しません。
ジッパー

1
ノードの下でスタックをログに記録する必要があります[2]
monika mevenkamp

5

これは多くの場合、現在のコンテキストからエラーをスローすることによって実現されます。次にlineNumber、andなどのプロパティのエラーオブジェクトを分析しますfileName(一部のブラウザにはあります)

function getErrorObject(){
  try { throw Error('') } catch(err) { return err; }
}

var err = getErrorObject();

err.fileName;
err.lineNumber; // or `err.line` in WebKit

callee.callerプロパティが非推奨であることを忘れないでください(そして、そもそもECMA 3 ed。に実際には決してなかった)。

また、関数の逆コンパイルは実装に依存するように指定されているため、予期しない結果が生じる可能性があることも覚えておいてください。私はここここでそれについて書きました


おかげで、必要なアプリケーションにこのコードを追加するのは少し問題があるようです。(いくつかのjsトレースフレームワーク)非推奨ではない、私が使用できる他のメソッドを知っていますか?
Tal

非推奨のに依存せずにエラーオブジェクトを検査できるはずですcallee.caller
kangax 2009

エラーをスローする必要はありません。(new Error).lineNumberを使用して、スクリプトの現在の行番号にアクセスします。
Eli Grey、

@Elijahそれは私がFF3で見るものです。一方、WebKitは、lineエラーがスローされた場合にのみ読み込まれます。
kangax 2009

callee.callerの代替は何ですか?関数名を取得する必要がある場合?
タル

4

少し遅れているようです:)ですが、議論はとても興味深いです。

function  errorHandler(error){
    this.errorMessage = error;
}
errorHandler.prototype. displayErrors = function(){
    throw new Error(this.errorMessage);
}

そして、あなたはこのようにあなたのコードをラップしています:

try{
if(condition){
    //whatever...
}else{
    throw new errorHandler('Some Error Message');
}
}catch(e){
    e.displayErrors();
}

ほとんどの場合、別の.jsファイルにエラーハンドラーがあります。

FirefoxまたはChromeのエラーコンソールで表示されたコード行番号(およびファイル名)は、デバッグを実行するために本当に必要な 'errorHandler'例外ではなく、 'Error'例外をスローする行(ファイル)であることがわかります簡単です。独自の例外をスローすることは素晴らしいことですが、特に類似したメッセージがある場合、大規模なプロジェクトでそれらを見つけることは非常に問題になる可能性があります。したがって、あなたができることは、実際の空のErrorオブジェクトへの参照をエラーハンドラーに渡すことであり、その参照は必要なすべての情報を保持します(たとえば、Firefoxでは、ファイル名や行番号などを取得できます)。 ;クロムでは、Errorインスタンスの 'stack'プロパティを読み取ると同様の結果になります。要するに、次のようなことができます。

function  errorHandler(error, errorInstance){
    this.errorMessage = error;
    this. errorInstance = errorInstance;
}
errorHandler.prototype. displayErrors = function(){
    //add the empty error trace to your message
    this.errorMessage += '  stack trace: '+ this. errorInstance.stack;
    throw new Error(this.errorMessage);
}

try{
if(condition){
    //whatever...
}else{
    throw new errorHandler('Some Error Message', new Error());
}
}catch(e){
    e.displayErrors();
}

これで、カスタム例外をスローした実際のファイルと行番号を取得できます。


4

行番号は実際には静的なものなので、ログに記録したいだけの場合は、gulpなどで前処理できます。私はまさにそれを行う小さなgulp プラグインを書きました:

var gulp = require('gulp');
var logLine = require('gulp-log-line');
gulp.task('log-line', function() {
    return gulp.src("file.js", {buffer : true})
    //Write here the loggers you use.
        .pipe(logLine(['console.log']))
        .pipe(gulp.dest('./build'))

})

gulp.task('default', ['log-line'])

これにより、console.logのすべてのログにファイル名と行が添付されるため、console.log(something)になりconsole.log('filePath:fileNumber', something)ます。利点は、ファイルを連結してトランスパイルできることです。


これは、トランスパイラーが使用されている状況(TypeScriptを使用している場合など)に最適な提案のようです。ありがとうございました!
アンディキング


3

デバッグの目的で、または開発中に(理由などにより)行番号を知りたい場合は、Firebug(Firefoxの拡張機能)を使用して例外をスローできます。

編集

本番環境で何らかの理由で本当にそれを行う必要がある場合は、各関数がその行を追跡できるように、JavaScriptファイルを前処理できます。コードのカバレッジを見つけるいくつかのフレームワークがこれを使用していることを知っています(JSCoverageなど)。

たとえば、元の通話が次のとおりだとします。

function x() {
  1 + 1;
  2 + 2;
  y();
}

あなたはそれを作るためにプリプロセッサを書くことができます:

function x() {
  var me = arguments.callee;
  me.line = 1;
  1 + 1;
  me.line = 2;
  2 + 2;
  me.line = 3;
  y();
}

次にy()、を使用arguments.callee.caller.lineして、次のような呼び出し元の行を知ることができます。

function y() {
  alert(arguments.callee.caller.line);
}

1
おかげで、サポート上の理由で本番環境でこれを行いたいと思います。メソッドまでのすべてのフローのコールスタックを確認できるコードをいくつか見つけましたが、メソッドが呼び出された行番号がありません。私はそのための簡単な解決策を推測しますか?
Tal

2

これは、このフォーラムで見つけた情報に基づいて私が書いたものです:

これはMyDebugNamespaceの一部であり、Debugは予約されているようで、名前空間名としては機能しません。

    var DEBUG = true;

...

    if (true == DEBUG && !test)
    {
        var sAlert = "Assertion failed! ";
        if (null != message)
            sAlert += "\n" + message;
        if (null != err)
            sAlert += "\n" + "File: " + err.fileName + "\n" + "Line: " + err.lineNumber;
        alert(sAlert);
    }

...

呼び出す方法:

    MyDebugNamespace.Assert(new Error(""), (null != someVar), "Something is wrong!")

この基本コードを呼び出す引数の数が可変の2つの関数を名前空間に含めて、呼び出しでメッセージまたはエラーを省略できるようにしました。

これは、Firefox、IE6、およびChromeで正常に機能し、fileNameおよびlineNumberが未定義として報告されます。


2

次のコードは、MozillaとChromeで動作します。

ファイルの名前と呼び出し元の行を示すログ関数。

log: function (arg) {
    var toPrint = [];
    for (var i = 0; i < arguments.length; ++i) {
        toPrint.push(arguments[i]);
    }

    function getErrorObject(){
        try { throw Error('') } catch(err) { return err; }
    }

    var err = getErrorObject(),
        caller;

    if ($.browser.mozilla) {
        caller = err.stack.split("\n")[2];
    } else {
        caller = err.stack.split("\n")[4];
    }

    var index = caller.indexOf('.js');

    var str = caller.substr(0, index + 3);
    index = str.lastIndexOf('/');
    str = str.substr(index + 1, str.length);

    var info = "\t\tFile: " + str;

    if ($.browser.mozilla) {
        str = caller;
    } else {
        index = caller.lastIndexOf(':');
        str = caller.substr(0, index);
    }
    index = str.lastIndexOf(':');
    str = str.substr(index + 1, str.length);
    info += " Line: " + str;
    toPrint.push(info);

    console.log.apply(console, toPrint);
}

何かが欠けているようです。私が取得:SyntaxError: function statement requires a name,log: function (arg) {
spiderplant0

このアイデアは好きですが、行番号が正しくありません。
ライアン

2

JavaScriptのカスタムエラーへの私の貢献:

  1. まず、Errorオブジェクトから継承する @BTの人に同意します-メッセージプロパティはどこにありますか?、適切にビルドする必要があります(実際には、jsオブジェクトライブラリを使用する必要があります。私のお気に入り:https : //github.com/jiem/my-class):

    window.g3 = window.g3 || {};
    g3.Error = function (message, name, original) {
         this.original = original;
         this.name = name || 'Error.g3';
         this.message = message || 'A g3.Error was thrown!';
         (original)? this.stack = this.original.stack: this.stack = null;
         this.message += '<br>---STACK---<br>' + this.stack;
     };
    
     var ClassEmpty = function() {};
     ClassEmpty.prototype = Error.prototype;
     g3.Error.prototype = new ClassEmpty();
     g3.Error.prototype.constructor = g3.Error;
  2. 次に、グローバルエラー処理関数(オプション)を定義する必要があります。そうしないと、最終的にエンジンに到達します。

    window.onerror = printError; 
    function printError(msg, url, line){
        document.getElementById('test').innerHTML = msg+'<br>at: '+url+'<br>line: '+line;
        return true;
    }
  3. 最後に、カスタムエラーを慎重にスローする必要があります。

    //hit it!
    //throw new g3.Error('Hey, this is an error message!', 'Error.Factory.g3');
    throw new g3.Error('Hey, this is an error message!', 'Error.Factory.g3', new Error());

のみ、3番目のパラメータを new Error()関数と行番号を含むスタックを見ることができる!

2では、関数はエンジンによってスローされたエラーも処理できます。

もちろん、本当の問題は、本当にそれが必要かどうか、そしていつかです。優雅な返還の場合があります(私の意見では99%)false十分であり、エラーがスローされた場合に表示される重要なポイントのみを残す。

例:http : //jsfiddle.net/centurianii/m2sQ3/1/


2

これが私のやり方です。FirefoxとChromeの両方でテストしました。これにより、関数の呼び出し元のファイル名と行番号を確認できます。

logFileAndLineNumber(new Error());

function logFileAndLineNumber(newErr)
{
   if(navigator.userAgent.indexOf("Firefox") != -1)
   {
      var originPath = newErr.stack.split('\n')[0].split("/");
      var fileNameAndLineNumber = originPath[originPath.length - 1].split(">")[0];
      console.log(fileNameAndLineNumber);
   }else if(navigator.userAgent.indexOf("Chrome") != -1)
   {
      var originFile = newErr.stack.split('\n')[1].split('/');
      var fileName = originFile[originFile.length - 1].split(':')[0];
      var lineNumber = originFile[originFile.length - 1].split(':')[1];
      console.log(fileName+" line "+lineNumber);
    }
}

2
console.log(new Error);

トラック全体が表示されます。


1

何かがどの行にあるかを判別するには、対象の特定の行を占めるコードのすべてのコードを検索し、対象の行の上から「\ n」文字を数えて、1を追加する必要があります。

私が書いているアプリケーションで実際にこれを行っています。これはHTMLのベストプラクティスバリデーターであり、まだ開発中ですが、関心のあるエラー出力プロセスは完了しています。

http://mailmarkup.org/htmlint/htmlint.html


関心のある特定の行が多くなる場合があります...同じメソッドが別のメソッドから数回呼び出された場合、どのようにして(その別のメソッドで)呼び出しがどこから到着したのかを知ることができますか?
Tal

インタプリタの外部から実行時にJavaScriptの解釈を分析することはできません。プログラムの実行パスを追跡するプログラムを書くこともできますが、実行するのはそのプログラムであり、分析するコードではありません。これは通常、ツールを使用して手動で実行される複雑なタスクです。コードの実行中にコードで何が起こっているのかを本当に知りたい場合は、決定が他のどの部分を実行しているかを通知するメタデータを画面に書き込みます。

-2

答えは簡単です。いいえ、いいえ(いいえ)。

JavaScriptがソースファイル/ URLの概念を実行している頃には、それはなくなっていました。

また、実行時にコード「行」の概念がJavascriptで意味を持たなくなるため、行番号を判別する方法もありません。

特定の実装はAPIフックを提供して、デバッグのためにそのような詳細への特権コードアクセスを許可する場合がありますが、これらのAPIは通常の標準Javascriptコードに公開されていません。


Firefoxでは例外にそのような情報が含まれています...少なくともFirefoxでは可能ですか?
ゾイドバーグ、

MS Scriptデバッガーを起動してブレークポイントを設定すると、呼び出しスタックに正確にどこから来たかが表示されます。これは特殊なフックのためですか?
Tal

「繰り返しになりますが、コードの「行」という概念は、Javascriptではもはや意味がありません。」え?JSはすでにconsole.log()を実行するたびに行番号を表示します
mikemaccana '17

@AnthonyWJonesはい。これは、やや絶対的な「いいえといいえ(いいえ)」とは正反対です。
mikemaccana 2012

@nailer:2009年にすべての主要なブラウザーで、私の答えはどのように矛盾していますか。手元にある質問は、JavaScriptの実行中に呼び出し先の行番号を検出することに関することを覚えておいてください。
AnthonyWJones 2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.