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'?
}
コールスタックを見つける方法はありますか?
このソリューションは非推奨であり、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());
}
ブラウザ固有のコードを使用して、スタック トレース全体を見つけることができます。良いことは、誰かがすでにそれを作っているということです。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 と呼び出し元関数の Name に関するヒントを提供します (ただし、これらはクロスブラウザーではありません)。
「Javascriptで」とおっしゃっていましたが、目的がデバッグであれば、ブラウザの開発者ツールをそのまま使う方が簡単だと思います。Chrome では次のように表示され
ます。スタックを調査したい場所にデバッガーをドロップするだけです。
完全なスタックトレースを取得できます。
arguments.callee.caller
arguments.callee.caller.caller
arguments.callee.caller.caller.caller
発信者がになるまでnull
。
注:再帰関数で無限ループが発生します。
要約する(そしてそれをより明確にする)..。
このコード:
function Hello() {
alert("caller is " + arguments.callee.caller.toString());
}
これと同等です:
function Hello() {
alert("caller is " + Hello.caller.toString());
}
関数の名前を「Hello」から「Ciao」に変更しても、すべてを機能させることができるので、明らかに最初のビットはより移植性があります。
後者の場合、呼び出された関数の名前をリファクタリングすることにした場合(Hello)、そのすべての出現箇所を変更する必要があります:(
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
これはかなり解決された質問のように見えますが、「厳密モード」では呼び出し先が許可されていないことが最近わかったので、自分で使用するために、呼び出された場所からパスを取得するクラスを作成しました。これは小さなヘルパー ライブラリの一部であり、コードをスタンドアロンで使用する場合は、呼び出し元のスタック トレースを返すために使用されるオフセットを変更します (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 Hello() {
alert(Hello.caller);
}
推奨され*arguments.callee.caller
ていないため、使用するarguments.caller
方が安全です...
これにアクセスしてみてください:
arguments.callee.caller.name
これのためにここに私のフィドルを追加したかった:
http://jsfiddle.net/bladnman/EhUm3/
これがクロム、サファリ、IE(10および8)であることをテストしました。正常に動作します。重要な関数は 1 つだけなので、大きなフィドルに怖がっている場合は、以下をお読みください。
注:このフィドルには、かなりの量の私自身の「ボイラープレート」があります。必要に応じて、すべてを削除して分割を使用できます。これは、私が頼りにするようになった、非常に安全な一連の機能です。
そこには「JSFiddle」テンプレートもあり、多くのフィドルを簡単にいじるために使用します。
コードではなく関数名だけが必要で、ブラウザーに依存しないソリューションが必要な場合は、次を使用します。
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()
、トリックを行います。
完全なスタックトレースを取得する関数は次のとおりです。
function stacktrace() {
var f = stacktrace;
var stack = 'Stack trace:';
while (f) {
stack += '\n' + f.name;
f = f.caller;
}
return stack;
}
ここでは、 以外のすべてが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>
次のコードを試してください。
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 で私のために働いた。
この問題を回避する別の方法は、呼び出し元の関数の名前をパラメーターとして渡すことです。
例えば:
function reformatString(string, callerName) {
if (callerName === "uid") {
string = string.toUpperCase();
}
return string;
}
これで、次のように関数を呼び出すことができます。
function uid(){
var myString = "apples";
reformatString(myString, function.name);
}
私の例では、関数名のハードコーディングされたチェックを使用していますが、switch ステートメントまたはその他のロジックを使用して、そこで必要なことを簡単に行うことができます。
次のコードが役立つと思います。
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
以前の回答はどれも私が探していたように機能しないため(文字列またはコールスタックとしての関数ではなく、最後の関数呼び出し元を取得する)、私のような人のためにここに私のソリューションを投稿し、これがうまくいくことを願っています:
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();
私の知る限り、このような特定の情報源からこれには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;
}
}
あなたの答えがあると思います:)。
なんらかの理由でその機能が本当に必要で、ブラウザ間の互換性があり、厳密なものを心配せずに前方互換性を持たせたい場合は、次の参照を渡します。
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
}