回答:どれが「クロージャ」でしょうか?
問題:どれが「クロージャ」でしょうか? - hogehoge の回答
期待させて申し訳ないですが、はっきりとした解等を定めていません。ということで解答ではなく、回答で。
クロージャの定義を以下の様に定めました。
引数以外の変数を実行時の環境ではなく、自身が定義された環境(静的スコープ)において解決することを特徴とする。
クロージャ - Wikipedia
JavaScriptの関数オブジェクトは定義時にスコープを定めてチェーンを形成します。このチェーンが変化することはありません。上記定義の言葉通りに考えるならば、答えは6, 7, 9以外の全てになると思います。
ただし、よくある説明では、関数の中で定義される関数オブジェクトのみを「クロージャ」と呼んでいる様に思えます。
var scope = "global"; function func1 () { return scope; } function foo () { var scope = "local"; return func1(); } foo(); // "global"
func1 が foo から実行されるわけですが、func1 は引数以外の変数を実行時の環境ではなく、自身が定義された環境
から変数scopeを割り出します。func1 が定義されたのはグローバルなスコープです。例え foo 関数の中で実行されようとも foo 関数内の変数がスコープに入ることはありません。
func1 は関数の中で定義されているわけではありません。定義にある様な特徴は持っているのに「クロージャ」ではないのでしょうか? ボクには分かりません。
例え、外部にグローバルのスコープしか持たない関数であっても、きちんと自身が定義された環境
を持っています。あえて「クロージャ」と呼ばれることはないかもしれません。しかし、その特徴は活かされないかもしれませんが、クロージャであることに変わりないと思うのです。
ただ、少し嫌な関数オブジェクトの定義方法があります。Functionコンストラクタと間接的なeval(indirect call)です。
Functionコンストラクタ
Functionコンストラクタは new Function(...) みたいなやつのことです。因みに、new Function(...)とFunction(...)に違いはありません、単なる引っかけとして2種類用意してみただけです。
コンストラクタの挙動によると、最後に以下の様に書かれています。
11. Return a new Function object created as specified in 13.2 passing P as the FormalParameterListopt and body as the FunctionBody. Pass in the Global Environment as the Scope parameter and strict as the Strict flag.
注目すべきは、ScopeをGlobal Environmentとしていることです。Global Environmentというのは要するにグローバルスコープのことです。ここ、普通のFunctionStatementなどでは、実行中の環境をScopeに定めているのですが、Functionコンストラクタではグローバルスコープ決め打ちです。
さて、定義時にこのスコープは定められ、しかも変化しません。しかし、そもそもの定義するスコープが自身が定義された環境
ではなくなっています。
よって、これはクロージャとは呼べないのではないでしょうか。(グローバルで定義されるFunctionコンストラクタによる関数作成はクロージャと呼べる...のか?)
間接的なeval
eval('(function(){ })')var e = eval; e('(function(){ })')
問題で上記2つを用意しましたが、挙動が変わります。
前者の場合は、evalされた時のスコープ環境を引き継ぎますが、後者はグローバルに設定されます。そのスコープがFunctionExpressionに渡ることになります。
前者は良いのですが、後者は Functionコンストラクタのときと同じで自身が定義された環境
と言えるのか怪しい感じになります。
ただ、スコープを歪めたのはevalであり、実行コードである関数式はそれを正確に引き継いだだけだとも言えます。難しいです。