220

arguments.callee.callerプロパティが JavaScript で廃止されたのはなぜですか?

これは JavaScript で追加され、その後廃止されましたが、ECMAScript では完全に省略されました。一部のブラウザー (Mozilla、IE) は常にサポートしており、サポートを削除する予定はありません。他のもの (Safari、Opera) はそのサポートを採用していますが、古いブラウザーでのサポートは信頼できません。

この貴重な機能を放置する正当な理由はありますか?

(または、呼び出し元の関数のハンドルを取得するためのより良い方法はありますか?)

4

4 に答える 4

259

JavaScriptの初期のバージョンでは名前付き関数式が許可されていなかったため、再帰関数式を作成できませんでした。

 // This snippet will work:
 function factorial(n) {
     return (!(n>1))? 1 : factorial(n-1)*n;
 }
 [1,2,3,4,5].map(factorial);


 // But this snippet will not:
 [1,2,3,4,5].map(function(n) {
     return (!(n>1))? 1 : /* what goes here? */ (n-1)*n;
 });

これを回避するために、次のarguments.calleeことができるように追加されました。

 [1,2,3,4,5].map(function(n) {
     return (!(n>1))? 1 : arguments.callee(n-1)*n;
 });

ただし、これは実際には本当に悪い解決策でした。これは(他の引数、呼び出し先、および呼び出し元の問題と組み合わせて)、一般的なケースではインライン化と末尾再帰を不可能にするためです(トレースなどを介して特定のケースでそれを達成できますが、最高のコードでも他の方法では必要ないチェックのため、最適ではありません)。もう1つの大きな問題は、再帰呼び出しが異なるthis値を取得することです。次に例を示します。

var global = this;
var sillyFunction = function (recursed) {
    if (!recursed)
        return arguments.callee(true);
    if (this !== global)
        alert("This is: " + this);
    else
        alert("This is the global");
}
sillyFunction();

とにかく、EcmaScript 3は、名前付き関数式を許可することでこれらの問題を解決しました。

 [1,2,3,4,5].map(function factorial(n) {
     return (!(n>1))? 1 : factorial(n-1)*n;
 });

これには多くの利点があります。

おっと、

arguments.callee.caller他のすべてに加えて、質問は、またはより具体的にはであることに気づきましたFunction.caller

いつでも、スタック上の任意の関数の最も深い呼び出し元を見つけることができます。前述したように、呼び出しスタックを確認すると、多数の最適化が不可能になるか、はるかに困難になるという1つの大きな影響があります。

例えば。f関数が不明な関数を呼び出さないことを保証できない場合、インライン化することはできませんf。基本的に、それは、些細なことでインライン化できなかった可能性のあるコールサイトが多数の警備員を蓄積することを意味します。

 function f(a, b, c, d, e) { return a ? b * c : d * e; }

jsインタープリターは、呼び出された時点で提供されたすべての引数が数値であることを保証できない場合、インライン化されたコードの前にすべての引数のチェックを挿入するか、関数をインライン化できません。

この特定のケースでは、スマートインタープリターは、チェックをより最適になるように再配置し、使用されない値をチェックしないようにする必要があります。ただし、多くの場合、それは不可能であるため、インライン化が不可能になります。

于 2008-10-25T01:51:40.203 に答える
89

arguments.callee.callerプロパティを使用しますが、非推奨ではありません。(現在の関数への参照を提供するだけです)Function.callerarguments.callee

  • Function.callerは、ECMA3 によると非標準ですが、現在の主要なブラウザすべてに実装されています。
  • arguments.caller 推奨されておらず、一部の現在の主要なブラウザー (Firefox 3 など) には実装されていません。Function.caller

したがって、状況は理想的とは言えませんが、すべての主要なブラウザーで Javascript の呼び出し関数にアクセスする場合は、名前付き関数参照で直接アクセスするか、プロパティを介して無名関数内からアクセスするかのいずれかで、プロパティを使用できます。Function.callerarguments.callee

于 2009-08-26T15:31:21.707 に答える
29

arguments.callee よりも名前付き関数を使用することをお勧めします。

 function foo () {
     ... foo() ...
 }

よりも良い

 function () {
     ... arguments.callee() ...
 }

名前付き関数は、 callerプロパティを介して呼び出し元にアクセスできます。

 function foo () {
     alert(foo.caller);
 }

よりも優れている

 function foo () {
     alert(arguments.callee.caller);
 }

非推奨になったのは、現在の ECMAScript設計原則によるものです。

于 2008-09-19T17:38:12.813 に答える