970
function main()
{
   Hello();
}

function Hello()
{
  // How do you find out the caller function is 'main'?
}

コールスタックを見つける方法はありますか?

4

35 に答える 35

1055

このソリューションは非推奨であり、MDN ドキュメントに従って使用しないでください。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller


function Hello()
{
    alert("caller is " + Hello.caller);
}

この機能は非標準であることに注意してFunction.callerください。

非標準
この機能は非標準であり、標準化過程にはありません。Web に面している実稼働サイトでは使用しないでください。すべてのユーザーに対して機能するとは限りません。また、実装間に大きな非互換性がある可能性があり、将来的に動作が変更される可能性があります。


以下は、最新の Javascript ではサポートされなくなった 2008 年の古い回答です。

function Hello()
{
    alert("caller is " + arguments.callee.caller.toString());
}
于 2008-11-11T09:07:16.327 に答える
160

スタックトレース

ブラウザ固有のコードを使用して、スタック トレース全体を見つけることができます。良いことは、誰かがすでにそれを作っているということです。GitHubのプロジェクト コードは次のとおりです。

しかし、すべてのニュースが良いわけではありません:

  1. スタック トレースを取得するのは非常に遅いため、注意してください (詳細については、こちらを参照してください)。

  2. スタック トレースを読みやすくするには、関数名を定義する必要があります。次のようなコードがある場合:

    var Klass = function kls() {
       this.Hello = function() { alert(printStackTrace().join('\n\n')); };
    }
    new Klass().Hello();
    

    Google Chrome は警告を発し... kls.Hello ( ...ますが、ほとんどのブラウザーはキーワードの直後に関数名を期待しfunction、匿名関数として扱います。Klass関数に名前を付けないと、Chrome でも名前を使用できなくklsなります。

    ちなみに、関数 printStackTrace にオプションを渡すことができます{guess: true}が、それを行っても実際の改善は見られませんでした。

  3. すべてのブラウザが同じ情報を提供するわけではありません。つまり、パラメーター、コード列などです。


呼び出し元関数名

ちなみに、呼び出し元の関数の名前だけが必要な場合 (ほとんどのブラウザーでは、IE ではなく)、次を使用できます。

arguments.callee.caller.name

ただし、この名前はfunctionキーワードの後の名前になることに注意してください。関数全体のコードを取得せずにそれ以上のものを取得する方法は (Google Chrome でも) 見つかりませんでした。


呼び出し元関数コード

残りの最良の回答を要約します (Pablo Cabrera、nourdine、および Greg Hewgill による)。クロスブラウザで本当に安全に使用できるのは、次のものだけです。

arguments.callee.caller.toString();

呼び出し元関数のコードが表示されます。悲しいことに、それだけでは十分ではありません。そのため、StackTrace と呼び出し元関数の Name に関するヒントを提供します (ただし、これらはクロスブラウザーではありません)。

于 2010-09-24T16:38:24.757 に答える
70

「Javascriptで」とおっしゃっていましたが、目的がデバッグであれば、ブラウザの開発者ツールをそのまま使う方が簡単だと思います。Chrome では次のように表示され ここに画像の説明を入力 ます。スタックを調査したい場所にデバッガーをドロップするだけです。

于 2015-02-03T00:28:59.773 に答える
53

完全なスタックトレースを取得できます。

arguments.callee.caller
arguments.callee.caller.caller
arguments.callee.caller.caller.caller

発信者がになるまでnull

注:再帰関数で無限ループが発生します。

于 2010-10-28T22:33:07.903 に答える
51

要約する(そしてそれをより明確にする)..。

このコード:

function Hello() {
    alert("caller is " + arguments.callee.caller.toString());
}

これと同等です:

function Hello() {
    alert("caller is " + Hello.caller.toString());
}

関数の名前を「Hello」から「Ciao」に変更しても、すべてを機能させることができるので、明らかに最初のビットはより移植性があります。

後者の場合、呼び出された関数の名前をリファクタリングすることにした場合(Hello)、そのすべての出現箇所を変更する必要があります:(

于 2009-04-06T13:47:43.603 に答える
23

Function.Caller を使用して呼び出し関数を取得できます。argument.caller を使用する古いメソッドは廃止されたと見なされます。

次のコードは、その使用法を示しています。

function Hello() { return Hello.caller;}

Hello2 = function NamedFunc() { return NamedFunc.caller; };

function main()
{
   Hello();  //both return main()
   Hello2();
}

古い argument.caller に関する注意: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/caller

Function.caller は非標準であることに注意してください: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller

于 2015-06-06T21:01:16.960 に答える
21

これはかなり解決された質問のように見えますが、「厳密モード」では呼び出し先が許可されていないことが最近わかったので、自分で使用するために、呼び出された場所からパスを取得するクラスを作成しました。これは小さなヘルパー ライブラリの一部であり、コードをスタンドアロンで使用する場合は、呼び出し元のスタック トレースを返すために使用されるオフセットを変更します (2 ではなく 1 を使用します)。

function ScriptPath() {
  var scriptPath = '';
  try {
    //Throw an error to generate a stack trace
    throw new Error();
  }
  catch(e) {
    //Split the stack trace into each line
    var stackLines = e.stack.split('\n');
    var callerIndex = 0;
    //Now walk though each line until we find a path reference
    for(var i in stackLines){
      if(!stackLines[i].match(/http[s]?:\/\//)) continue;
      //We skipped all the lines with out an http so we now have a script reference
      //This one is the class constructor, the next is the getScriptPath() call
      //The one after that is the user code requesting the path info (so offset by 2)
      callerIndex = Number(i) + 2;
      break;
    }
    //Now parse the string for each section we want to return
    pathParts = stackLines[callerIndex].match(/((http[s]?:\/\/.+\/)([^\/]+\.js)):/);
  }

  this.fullPath = function() {
    return pathParts[1];
  };

  this.path = function() {
    return pathParts[2];
  };

  this.file = function() {
    return pathParts[3];
  };

  this.fileNoExt = function() {
    var parts = this.file().split('.');
    parts.length = parts.length != 1 ? parts.length - 1 : 1;
    return parts.join('.');
  };
}
于 2014-03-04T07:14:20.333 に答える
20
function Hello() {
    alert(Hello.caller);
}
于 2008-11-11T10:56:21.177 に答える
18

推奨され*arguments.callee.callerていないため、使用するarguments.caller方が安全です...

于 2008-11-11T09:50:39.297 に答える
11

これにアクセスしてみてください:

arguments.callee.caller.name
于 2008-11-11T10:19:20.237 に答える
7

これのためにここに私のフィドルを追加したかった:

http://jsfiddle.net/bladnman/EhUm3/

これがクロム、サファリ、IE(10および8)であることをテストしました。正常に動作します。重要な関数は 1 つだけなので、大きなフィドルに怖がっている場合は、以下をお読みください。

注:このフィドルには、かなりの量の私自身の「ボイラープレート」があります。必要に応じて、すべてを削除して分割を使用できます。これは、私が頼りにするようになった、非常に安全な一連の機能です。

そこには「JSFiddle」テンプレートもあり、多くのフィドルを簡単にいじるために使用します。

于 2012-09-07T15:32:01.747 に答える
6

コードではなく関数名だけが必要で、ブラウザーに依存しないソリューションが必要な場合は、次を使用します。

var callerFunction = arguments.callee.caller.toString().match(/function ([^\(]+)/)[1];

配列に [1] 要素がないため、呼び出し元関数がない場合、上記はエラーを返すことに注意してください。回避するには、以下を使用します。

var callerFunction = (arguments.callee.caller.toString().match(/function ([^\(]+)/) === null) ? 'Document Object Model': arguments.callee.caller.toString().match(/function ([^\(]+)/)[1], arguments.callee.toString().match(/function ([^\(]+)/)[1]);
于 2012-03-15T03:46:28.250 に答える
5

PhoneGap/Androidでは動作していないnameようです。しかしarguments.callee.caller.toString()、トリックを行います。

于 2014-04-08T17:59:18.403 に答える
4

完全なスタックトレースを取得する関数は次のとおりです。

function stacktrace() {
var f = stacktrace;
var stack = 'Stack trace:';
while (f) {
  stack += '\n' + f.name;
  f = f.caller;
}
return stack;
}
于 2016-04-13T11:12:59.750 に答える
4

ここでは、 以外のすべてがfunctionnameから取り除かれcaller.toString()、RegExp が使用されます。

<!DOCTYPE html>
<meta charset="UTF-8">
<title>Show the callers name</title><!-- This validates as html5! -->
<script>
main();
function main() { Hello(); }
function Hello(){
  var name = Hello.caller.toString().replace(/\s\([^#]+$|^[^\s]+\s/g,'');
  name = name.replace(/\s/g,'');
  if ( typeof window[name] !== 'function' )
    alert ("sorry, the type of "+name+" is "+ typeof window[name]);
  else
    alert ("The name of the "+typeof window[name]+" that called is "+name);
}
</script>
于 2012-09-12T08:35:44.517 に答える
1

次のコードを試してください。

function getStackTrace(){
  var f = arguments.callee;
  var ret = [];
  var item = {};
  var iter = 0;

  while ( f = f.caller ){
      // Initialize
    item = {
      name: f.name || null,
      args: [], // Empty array = no arguments passed
      callback: f
    };

      // Function arguments
    if ( f.arguments ){
      for ( iter = 0; iter<f.arguments.length; iter++ ){
        item.args[iter] = f.arguments[iter];
      }
    } else {
      item.args = null; // null = argument listing not supported
    }

    ret.push( item );
  }
  return ret;
}

Firefox-21 と Chromium-25 で私のために働いた。

于 2013-06-22T20:33:26.763 に答える
1

この問題を回避する別の方法は、呼び出し元の関数の名前をパラメーターとして渡すことです。

例えば:

function reformatString(string, callerName) {

    if (callerName === "uid") {
        string = string.toUpperCase();
    }

    return string;
}

これで、次のように関数を呼び出すことができます。

function uid(){
    var myString = "apples";

    reformatString(myString, function.name);
}

私の例では、関数名のハードコーディングされたチェックを使用していますが、switch ステートメントまたはその他のロジックを使用して、そこで必要なことを簡単に行うことができます。

于 2016-03-04T15:29:18.073 に答える
1

次のコードが役立つと思います。

window.fnPureLog = function(sStatement, anyVariable) {
    if (arguments.length < 1) { 
        throw new Error('Arguments sStatement and anyVariable are expected'); 
    }
    if (typeof sStatement !== 'string') { 
        throw new Error('The type of sStatement is not match, please use string');
    }
    var oCallStackTrack = new Error();
    console.log(oCallStackTrack.stack.replace('Error', 'Call Stack:'), '\n' + sStatement + ':', anyVariable);
}

コードを実行します。

window.fnPureLog = function(sStatement, anyVariable) {
    if (arguments.length < 1) { 
        throw new Error('Arguments sStatement and anyVariable are expected'); 
    }
    if (typeof sStatement !== 'string') { 
        throw new Error('The type of sStatement is not match, please use string');
    }
    var oCallStackTrack = new Error();
    console.log(oCallStackTrack.stack.replace('Error', 'Call Stack:'), '\n' + sStatement + ':', anyVariable);
}

function fnBsnCallStack1() {
    fnPureLog('Stock Count', 100)
}

function fnBsnCallStack2() {
    fnBsnCallStack1()
}

fnBsnCallStack2();

ログは次のようになります。

Call Stack:
    at window.fnPureLog (<anonymous>:8:27)
    at fnBsnCallStack1 (<anonymous>:13:5)
    at fnBsnCallStack2 (<anonymous>:17:5)
    at <anonymous>:20:1 
Stock Count: 100
于 2017-04-28T07:27:45.343 に答える
1

以前の回答はどれも私が探していたように機能しないため(文字列またはコールスタックとしての関数ではなく、最後の関数呼び出し元を取得する)、私のような人のためにここに私のソリューションを投稿し、これがうまくいくことを願っています:

function getCallerName(func)
{
  if (!func) return "anonymous";
  let caller = func.caller;
  if (!caller) return "anonymous";
  caller = caller.toString();
  if (!caller.trim().startsWith("function")) return "anonymous";
  return caller.substring(0, caller.indexOf("(")).replace("function","");
}


//  Example of how to use "getCallerName" function

function Hello(){
console.log("ex1  =>  " + getCallerName(Hello));
}

function Main(){
Hello();

// another example
console.log("ex3  =>  " + getCallerName(Main));
}

Main();

于 2018-10-22T09:19:36.073 に答える
1

私の知る限り、このような特定の情報源からこれには2つの方法があります-

  1. 引数.呼び出し元

    function whoCalled()
    {
        if (arguments.caller == null)
           console.log('I was called from the global scope.');
        else
           console.log(arguments.caller + ' called me!');
    }
    
  2. Function.caller

    function myFunc()
    {
       if (myFunc.caller == null) {
          return 'The function was called from the top!';
       }
       else
       {
          return 'This function\'s caller was ' + myFunc.caller;
        }
    }
    

あなたの答えがあると思います:)。

于 2016-03-28T05:34:40.950 に答える
0

なんらかの理由でその機能が本当に必要で、ブラウザ間の互換性があり、厳密なものを心配せずに前方互換性を持たせたい場合は、次の参照を渡します。

function main()
{
   Hello(this);
}

function Hello(caller)
{
    // caller will be the object that called Hello. boom like that... 
    // you can add an undefined check code if the function Hello 
    // will be called without parameters from somewhere else
}
于 2015-11-03T01:22:49.130 に答える