function main()
{
Hello();
}
function Hello()
{
// How do you find out the caller function is 'main'?
}
呼び出しスタックを見つける方法はありますか?
function main()
{
Hello();
}
function Hello()
{
// How do you find out the caller function is 'main'?
}
呼び出しスタックを見つける方法はありますか?
回答:
function Hello()
{
alert("caller is " + Hello.caller);
}
この機能は標準ではないことに注意してくださいFunction.caller
。
非標準
この機能は非標準であり、標準化されていません。Webに面している本番サイトでは使用しないでください。すべてのユーザーに対して機能するわけではありません。また、実装間に大きな非互換性があり、動作が将来変更される可能性があります。
以下は、2008年からの古い回答で、現在のJavascriptではサポートされていません。
function Hello()
{
alert("caller is " + arguments.callee.caller.toString());
}
arguments.callee.caller.name
関数の名前を取得します。
'use strict';
すると役立つ場合があります。
arguments
ストリクトモードの関数内からアクセスできますが、それを廃止するのは愚かです。外部からのfunction.argumentsからではありません。また、名前付き引数がある場合、arguments [i]形式は、関数内の名前付きバージョンに加えた変更を追跡しません。
ブラウザ固有のコードを使用して、スタックトレース全体を見つけることができます。良いことは、誰かがすでにそれを作ったことです。これがGitHubのプロジェクトコードです。
しかし、すべてのニュースが良いわけではありません。
スタックトレースを取得するのは本当に遅いので注意してください(詳しくはこちらをご覧ください)
スタックトレースを読みやすくするには、関数名を定義する必要があります。次のようなコードがある場合:
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}
が、それを行っても実際の改善はありませんでした。
すべてのブラウザが同じ情報を提供するわけではありません。つまり、パラメーター、コード列などです。
ちなみに、(ほとんどのブラウザでは、IEではなく)呼び出し関数の名前だけが必要な場合は、次のように使用できます。
arguments.callee.caller.name
ただし、この名前はfunction
キーワードの後の名前になることに注意してください。(Google Chromeでさえ)関数全体のコードを取得せずにそれ以上のものを取得する方法は見つかりませんでした。
そして、残りの最良の回答を要約します(Pablo Cabrera、nourdine、およびGreg Hewgillによる)。使用できる唯一のクロスブラウザで本当に安全なものは:
arguments.callee.caller.toString();
呼び出し元関数のコードが表示されます。残念なことに、それだけでは十分ではありません。そのため、StackTraceと呼び出し元の関数の名前(クロスブラウザーではありません)のヒントを提供します。
Function.caller
ただし、厳密モードでは機能しません。
「Javascriptで」とおっしゃっていましたが、デバッグが目的であれば、ブラウザの開発者ツールを使用する方が簡単だと思います。これはChromeでの表示です: スタックを調査する場所にデバッガーをドロップするだけです。
要約すると(そしてそれをより明確にするために)...
このコード:
function Hello() {
alert("caller is " + arguments.callee.caller.toString());
}
これと同等です:
function Hello() {
alert("caller is " + Hello.caller.toString());
}
関数の名前を "Hello"から "Ciao"に変更しても、全体が機能するため、最初のビットの方が移植性が高いことは明らかです。
後者では、呼び出された関数(Hello)の名前をリファクタリングする場合、そのすべての出現を変更する必要があります:(
完全なスタックトレースを取得できます。
arguments.callee.caller
arguments.callee.caller.caller
arguments.callee.caller.caller.caller
発信者がnull
いるまで。
注:再帰関数で無限ループが発生します。
私は通常使用します (new Error()).stack
Chromeでします。これは、呼び出し元が関数を呼び出した場所の行番号も提供するので便利です。欠点は、スタックの長さが10に制限されていることです。そのため、最初にこのページにアクセスしました。
(私はこれを使用して、実行中に低レベルのコンストラクターでコールスタックを収集し、後で表示してデバッグするため、数千回ヒットするため、ブレークポイントを設定しても意味がありません)
'use strict';
です。必要な情報を提供してくれた-ありがとう!
IE <11で実行しない場合は、console.trace()が適しています。
function main() {
Hello();
}
function Hello() {
console.trace()
}
main()
// Hello @ VM261:9
// main @ VM261:4
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
Cannot access caller property of a strict mode function
私はこれを行います:
function Hello() {
console.trace();
}
function Hello() {
alert(Hello.caller);
}
arguments.callee.caller.toString()
は非推奨であるため*arguments.callee.caller
、使用する方が安全です ...arguments.caller
arguments.callee
ES5でも非推奨になり、strictモードで削除されました。
arguments.callee
今より良い解決された問題の悪い解決策だったdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
これはかなり解決された質問のように見えますが、私は最近、呼び出し先が「ストリクトモード」で許可されていないことを知りました。これは小さなヘルパーライブラリの一部であり、スタンドアロンのコードを使用する場合は、呼び出し元のスタックトレースを返すために使用されるオフセットを変更します(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('.');
};
}
function a(){ function b(){ function c(){ return ScriptPath(); } return c(); } return b(); } a()
コンソールでは機能しません(ファイルで試したことはありません)が、合理的な考えがあるようです。とにかく可視性のために賛成票を投じるべきです。
caller
厳格モードでは禁止されています。(非標準)スタックを使用した代替方法は次のError
とおりです。
次の関数は、Firefox 52とChrome 61-71で機能するようですが、その実装では2つのブラウザーのログ形式について多くの仮定がなされており、例外をスローして2つの正規表現を実行する可能性があるため、注意して使用する必要があります行われる前のマッチング。
'use strict';
const fnNameMatcher = /([^(]+)@|at ([^(]+) \(/;
function fnName(str) {
const regexResult = fnNameMatcher.exec(str);
return regexResult[1] || regexResult[2];
}
function log(...messages) {
const logLines = (new Error().stack).split('\n');
const callerName = fnName(logLines[1]);
if (callerName !== null) {
if (callerName !== 'log') {
console.log(callerName, 'called log with:', ...messages);
} else {
console.log(fnName(logLines[2]), 'called log with:', ...messages);
}
} else {
console.log(...messages);
}
}
function foo() {
log('hi', 'there');
}
(function main() {
foo();
}());
私はここに私のフィドルを追加したかった:
http://jsfiddle.net/bladnman/EhUm3/
私はこれをクロム、サファリ、IE(10と8)でテストしました。正常に動作します。重要な機能は1つしかないので、大きなフィドルに怖がってしまった場合は、以下をお読みください。
注:このフィドルには、私自身の「定型文」がかなりあります。それをすべて削除し、必要に応じてスプリットを使用できます。これは、私が信頼できるようになった、非常に安全な一連の機能です。
また、そこには「JSFiddle」テンプレートがあり、私は多くのフィドルで簡単に操作するために使用しています。
String.prototype.trim = trim;
コードではなく関数名だけが必要で、ブラウザに依存しないソリューションが必要な場合は、以下を使用します。
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]);
PhoneGap / Androidではname
動作していないように見えることをお知らせください。しかしarguments.callee.caller.toString()
、トリックを行います。
ここでは、RegExpを使用して、以外のすべてがfunctionname
から削除されていcaller.toString()
ます。
<!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>
ここに完全なスタックトレースを取得する関数があります:
function stacktrace() {
var f = stacktrace;
var stack = 'Stack trace:';
while (f) {
stack += '\n' + f.name;
f = f.caller;
}
return stack;
}
heystewartの回答とJiarongWuの回答の両方で、Error
オブジェクトはにアクセスできると述べましたstack
。
次に例を示します。
function main() {
Hello();
}
function Hello() {
var stack;
try {
throw new Error();
} catch (e) {
stack = e.stack;
}
// N.B. stack === "Error\n at Hello ...\n at main ... \n...."
var m = stack.match(/.*?Hello.*?\n(.*?)\n/);
if (m) {
var caller_name = m[1];
console.log("Caller is:", caller_name)
}
}
main();
異なるブラウザでは、スタックが異なる文字列形式で表示されます。
Safari : Caller is: main@https://stacksnippets.net/js:14:8
Firefox : Caller is: main@https://stacksnippets.net/js:14:3
Chrome : Caller is: at main (https://stacksnippets.net/js:14:3)
IE Edge : Caller is: at main (https://stacksnippets.net/js:14:3)
IE : Caller is: at main (https://stacksnippets.net/js:14:3)
ほとんどのブラウザはスタックを設定します var stack = (new Error()).stack
。Internet Explorerでは、スタックは定義されていません。スタックを取得するには、実際の例外をスローする必要があります。
結論:オブジェクトのを使用しstack
て、「main」が「Hello」の呼び出し元であると判断することができ Error
ます。実際、callee
/ caller
アプローチが機能しない場合でも機能します。また、ソースファイルや行番号などのコンテキストも表示されます。ただし、ソリューションをクロスプラットフォームにするための努力が必要です。
Node.jsではFunction.callerを使用できないことに注意してください。代わりにcaller-idパッケージを使用してください。例えば:
var callerId = require('caller-id');
function foo() {
bar();
}
function bar() {
var caller = callerId.getData();
/*
caller = {
typeName: 'Object',
functionName: 'foo',
filePath: '/path/of/this/file.js',
lineNumber: 5,
topLevelFlag: true,
nativeFlag: false,
evalFlag: false
}
*/
}
次のコードを試してください:
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で私のために働いた。
arguments.callee
長年にわたって非推奨となっています。
この問題を回避するもう1つの方法は、呼び出し元の関数の名前をパラメーターとして渡すだけです。
例えば:
function reformatString(string, callerName) {
if (callerName === "uid") {
string = string.toUpperCase();
}
return string;
}
これで、次のように関数を呼び出すことができます。
function uid(){
var myString = "apples";
reformatString(myString, function.name);
}
私の例では、関数名のハードコーディングされたチェックを使用していますが、switchステートメントやその他のロジックを使用して、目的の動作を簡単に実行できます。
私の知る限り、このような特定のソースからこれを行うには2つの方法があります
function whoCalled()
{
if (arguments.caller == null)
console.log('I was called from the global scope.');
else
console.log(arguments.caller + ' called me!');
}
function myFunc()
{
if (myFunc.caller == null) {
return 'The function was called from the top!';
}
else
{
return 'This function\'s caller was ' + myFunc.caller;
}
}
あなたがあなたの答えを持っていると思います:)。
上記のすべてのソリューションがロケットサイエンスのように見える理由。その間、それはこのスニペットよりも複雑であってはなりません。この男のすべてのクレジット
JavaScriptで呼び出し元関数をどのようにして見つけますか?
var stackTrace = function() {
var calls = [];
var caller = arguments.callee.caller;
for (var k = 0; k < 10; k++) {
if (caller) {
calls.push(caller);
caller = caller.caller;
}
}
return calls;
};
// when I call this inside specific method I see list of references to source method, obviously, I can add toString() to each call to see only function's content
// [function(), function(data), function(res), function(l), function(a, c), x(a, b, c, d), function(c, e)]
私はこの質問と現在の報奨金の両方にこの質問で対処しようとしています。
バウンティでは、呼び出し元がストリクトモードで取得される必要があります。これが行われたことを確認できる唯一の方法は、ストリクトモードの外部で宣言された関数を参照することです。
たとえば、以下は非標準ですが、以前のバージョン(2016年3月29日)および現在のバージョン(2018年8月1日)のChrome、Edge、Firefoxでテストされています。
function caller()
{
return caller.caller.caller;
}
'use strict';
function main()
{
// Original question:
Hello();
// Bounty question:
(function() { console.log('Anonymous function called by ' + caller().name); })();
}
function Hello()
{
// How do you find out the caller function is 'main'?
console.log('Hello called by ' + caller().name);
}
main();
何らかの理由で本当に機能が必要で、ブラウザ間の互換性を確保し、厳密なことを心配せずに上位互換性を確保したい場合は、次の参照を渡します。
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
}
次のコードが役立つと思います。
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