.callee 非推奨
このプロパティは、現在実行中の関数を格納します。
説明
calleeはargumentsオブジェクトのプロパティです。 これは、関数の本文内部から、現在実行中の関数を参照するために使用することが出来ます。 これは名前を持たない関数式("匿名関数"とも呼ばれます)のように、関数名を知ることが出来ない際に便利です。
警告: ECMAScript第5版(ES5)ではstrict modeにおいて、 arguments.callee()の使用を禁止しています。 自身の関数を呼び出さなければいけない際に、関数式の名前が与えられている、または関数定義が使用されているのであれば、 arguments.callee()の使用は避けて下さい。
何故、arguments.calleeはES5のstrict modeから削除されたのでしょうか?
(Stack Overflow answer by olliejより、転用)JavaScriptの早期のバージョンでは、関数式への名前付けが許可されておらず、 そのため関数式を再帰処理することが出来ませんでした。
例えば、下記の文法は動作していましたが、
function factorial (n) {
return !(n > 1) ? 1 : factorial(n - 1) * n;
}
[1,2,3,4,5].map(factorial);
下記のように名前が無いと、動作させることが出来ませんでした。
[1,2,3,4,5].map(function (n) {
return !(n > 1) ? 1 : /* ここはどうすれば? */ (n - 1) * n;
});
これを解決するために、arguments.calleeが使用されていました。
[1,2,3,4,5].map(function (n) {
return !(n > 1) ? 1 : arguments.callee(n - 1) * n;
});
ただし、これがインライン化を作成する(その他のargumentsのcalleeとcaller問題に関連して)として(翻訳に自信なし)、
実際に非常に悪い解決策であり、多くのケースで最後の再帰が実行不可能になります。
(トレーシング等を通して選択するケースで目的を達成出来るかもしれませんが、
それでも、それが本当に必要であるかを調べるのが最善のコードであると言えます。(翻訳に自信なし))
別の大きな問題として、再帰呼び出しは異なる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;
});
これは、様々な恩恵をもたらしてくれます。
- この関数は、内部のコードから別のものとして呼び出される事が可能です。
- 外部スコープ内に変数を作成しません。(IE8とそれ以前のバージョンを除く)
- argumentsオブジェクトへアクセスするよりも、パフォーマンスが向上します。
非推奨とされた別の機能に、arguments.callee.caller
、特にFunction.caller
があります。
これは何故でしょうか?
スタック内のある関数で最深層の呼び出しを見つけることが出来る時点で、
前述したように見つけられたコールスタックは、ある一つの重大な影響を持ち合わせ、
これは多数の最適化が不可能なものを作り出すか、またはそれを非常に、非常に困難にします。(翻訳に自信なし)
例えば、もし関数fが匿名関数を呼び出さないことを保証出来ないのであれば、
fをインライン化することは出来ません。(翻訳に自信なし)
つまり、取るに足らないインライン化が行われたかもしれない呼び出し場所で、
非常に多くの保護(監視?)が蓄積されてしまうことを意味します。(翻訳に自信なし)
function f (a, b, c, d, e) { return a ? b * c : d * e; }
もしJavaScriptインタプリタが提供された引数の全てが、 呼び出しが作成された時点で数値であることを保証出来ない場合、 コードのインライン化の前に全ての引数のためにチェックを行う処理を差し込むか、 さもなくばその関数のインライン化は不可能になります。(翻訳に自信なし) こういった特定のケースは、現在の優れたインタプリタであれば、 より最適化するためのチェックを再編集し、使用されない値ではチェックをしないといった事が出来るはずです。(翻訳に自信なし) ただし、多くのケースでこれは無理な話であり、それ故インライン化が不可能になります。
例
匿名再帰関数内でのarguments.calleeの使用
再帰関数は、自身を参照出来なければいけません。 通常は、自身の名前によって自身を参照します。 ただし、匿名関数(関数式またはFunctionコンストラクタによって作成される)は名前を持ちません。 それ故、参照する変数が存在しない場合には、arguments.calleeだけが自身を参照する唯一の方法になります。
下記の例は、順に階乗関数を定義して返す、関数を定義します。 この例は全く実用的なものではありませんが、 名前付き関数式でこれと同じ結果を得ることはほぼ無理でしょう。(翻訳に自信なし)
function create() {
return function(n) {
if (n <= 1)
return 1;
return n * arguments.callee(n - 1);
};
}
var result = create()(5); // returns 120 (5 * 4 * 3 * 2 * 1)
良い代替が存在しないarguments.calleeの使用について
ただし、下記のようなケースではarguments.calleeに変わるものが存在しないため、 これを非推奨にすること自体がバグなのかもしれません。(翻訳に自信なし)(bug 725398参照)
function createPerson (sIdentity) {
var oPerson = new Function("alert(arguments.callee.identity);");
oPerson.identity = sIdentity;
return oPerson;
}
var john = createPerson("John Smith");
john();
仕様
ブラウザ互換性
機能 | Chrome | Firefox (Gecko) |
IE | Opera | Safari |
---|---|---|---|---|---|
基本 | ◯ | ◯ | ◯ | ◯ | ◯ |
機能 | Android | Chrome for Android |
Firefox Mobile |
IE Mobile |
Opera Mobile |
Safari Mobile |
---|---|---|---|---|---|---|
基本 | ◯ | ◯ | ◯ | ◯ | ◯ | ◯ |
関連項目
© 2017 Mozilla Contributors
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
このページは、ページトップのURL先のMozilla Developer Network(以下、MDN)のコンテンツを翻訳した内容を基に構成されています。 構成について異なる点も含まれますので、下記の項目を確認し、必要に応じて元のコンテンツをご確認ください。 もし、誤訳などの間違いを見つけましたら、 @tomofまで教えていただければ幸いです。
- 特定のブラウザに特化しすぎている情報やあまりにも古い情報、 または試験的に導入されているようなAPIや機能については、省略していることがあります。
- 例やデモについて、実際にページ内で動作させる関係で一部ソースコードを変更している場合や、 その例で使用しているコンテンツの単語や文章などを日本人向けに変更しいてる場合があります。
- MDNの更新頻度が高いため、元のコンテンツと比べ情報が古くなっている可能性があります。
- "訳注:"などの断わりを入れた上で、日本人向けの情報の追記を行っている事があります。