jsでQuineしてて、arguments.callee()
なるものを知った。(それまで知らなかった)
しかし、これES5以降ではエラーになるらしい。つまり使っちゃダメ。
その理由を詳しく調べてみた。
そもそもarguments.callee()とは?
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/arguments/callee#Why_was_arguments.callee_removed_from_ES5_strict_mode
callee
はarguments
オブジェクトのプロパティです。関数の本体の内部で現在実行中の関数を参照するために使用します。これは関数名が不明であるとき、たとえば名前のない関数式(「無名関数」)の内部などで便利です。
要するに無名関数を再帰的に呼び出したい時に、有用。
バグの温床になる!?
例えば、こんなコードがあったとしよう。!recursed
がtrue
の時、funcA
が再帰的に呼び出される。
var global = this;
console.log(this);
var funcA = function (recursed) {
if (!recursed) return arguments.callee(true);
if ( this != global) {
console.log(this);
} else {
console.log("thisはglobalのまま");
}
}
funcA();
①funcA
が引数なしで呼ばれる。this
はもちろんglobal
。recursed
はundefined
なので、!recursed
はtrue
。
よって、funcA
が再帰的に呼び出される。呼び出されたfuncA
は、
- 引数は
true
- レシーバが
arguments
なので、this
は最初に呼び出されたarguments
。
②引数のrecursed
はtrue
。
この時点でのthis
はglobal
ではない(上述の通りarguments
)ため、if文の真の方が実行される。
→初めの呼び出しと、再帰的に呼び出された2回目とでthis
の値が変わる!
出力はこんな感じになる
2行目と7行目でthis
の値が変わる
まとめ
この最初の呼び出しと再帰での呼び出しでthis
が変わるという動作は思わぬバグを引き起こすため、名前付きの関数式を使うことが推奨されるようになったというのが理由のよう。
参考
arguments.callee - JavaScript | MDN
arguments.callee プロパティは現在実行中の関数を示します。
(なんか中途半端に日本語化されてますw)