1. ホーム
  2. ジャバスクリプト

[解決済み】JavaScriptでarguments.callee.callerプロパティが非推奨になったのはなぜですか?

2022-04-07 18:43:29

質問

なぜ arguments.callee.caller プロパティは非推奨ですか?

JavaScriptでは追加された後、非推奨となりましたが、ECMAScriptでは完全に省かれました。 一部のブラウザ (Mozilla, IE) は常にこれをサポートしており、サポートを終了する予定もないようです。 その他のブラウザ(Safari、Opera)はサポートを採用しているが、古いブラウザでのサポートは信頼性に欠ける。

この貴重な機能を手つかずにしておく理由はあるのでしょうか?

(あるいは、呼び出し元の関数を把握するもっと良い方法はないでしょうか?)

どのように解決するのですか?

初期の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;
 });

しかし、これは実際には悪い解決策でした。なぜなら、(他の引数、カルリー、呼び出し元の問題と合わせて)インライン化と末尾再帰は一般的なケースでは不可能だからです(トレースなどで一部のケースでは実現できますが、そうでなければ必要ないチェックのため、最高のコードでさえ最適ではなくなります)。 もうひとつの大きな問題は、再帰的な呼び出しを行うと、別の 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;
 });

これには数々のメリットがあります。

  • この関数は、他の関数と同様にコード内部から呼び出すことができます。

  • 名前空間を汚染しない。

  • の値は this は変更されません。

  • よりパフォーマンスが向上します( 引数オブジェクト は高価です)。

おっとっと。

今気づいたのですが、質問の内容に加えて arguments.callee.caller または、より具体的には Function.caller .

どの時点でも、スタック上にある関数の最深部の呼び出し元を見つけることができます。上で述べたように、呼び出しスタックを見ることは、一つの大きな効果があります。

例えば、ある関数が、その関数が、その関数が、その関数が、その関数が、その関数が、と保証できない場合。 f が未知の関数を呼び出さないようにするためには、インラインの f . 基本的には、些細なことでインライン化できたかもしれない呼び出し先が、大量のガードを蓄積していくことを意味します。

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

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

この場合、賢いインタープリターなら、より最適になるようにチェックを並べ替え、使わない値はチェックしないようにできるはずです。 しかし、多くの場合、それは不可能であり、したがってインライン化も不可能になります。