[解決済み】JavaScriptでarguments.callee.callerプロパティが非推奨になったのはなぜですか?
質問
なぜ
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インタプリタが、呼び出しの時点で提供された引数がすべて数字であることを保証できない場合、インラインコードの前にすべての引数に対するチェックを挿入するか、関数をインライン化できないようにする必要があります。
この場合、賢いインタープリターなら、より最適になるようにチェックを並べ替え、使わない値はチェックしないようにできるはずです。 しかし、多くの場合、それは不可能であり、したがってインライン化も不可能になります。
関連
-
[解決済み】コンソールがUnterminated JSX contentsエラーを投げる【終了しました
-
[解決済み】Reactのeslintエラーはpropsの検証で見つからない
-
[解決済み】PhantomJS 2.1.1を使用してReactJSアプリケーションをレンダリングできない理由とは?
-
[解決済み] JavaScriptで "use strict "は何をするのか、その根拠は?
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] あるJavaScriptファイルを他のJavaScriptファイルにインクルードするにはどうすればよいですか?
-
[解決済み] JavaScriptでオブジェクトをディープクローンする最も効率的な方法は何ですか?
-
[解決済み] とは何ですか! (not not)演算子とは何ですか?
-
[解決済み] JavaScriptで現在のURLを取得する?
-
[解決済み】JavaScriptで文字列の出現箇所をすべて置換する方法
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】document.getElementByIDは関数ではありません。
-
[解決済み] Uncaught Invariant Violation: 前のレンダリング中よりも多くのフックをレンダリングした
-
[解決済み】webpack: モジュールが見つかりません。Error: 解決できない(相対パスで)
-
[解決済み】JavaScriptのinnerHTMLで要素が更新されない
-
[解決済み】ある要素を別の要素に移動させるには?
-
[解決済み】SyntaxError: ChromeのJavascriptコンソールでUnexpected Identifierが発生する。
-
[解決済み】エラー:リスン EACCES 0.0.0.0:80 OSx Node.js
-
[解決済み】JavaScriptで相対URLへのリダイレクトを行う
-
[解決済み] JavaScriptで呼び出し元の関数を調べるには?
-
[解決済み】例外をスローしたときにJavaScriptのスタックトレースを取得するにはどうすればよいですか?