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)



