38745


クロージャに関して読んでいると宣言時の関数外部の変数状態も保存できる仕組みそのものを指している時もあれば、

[code]

    function outer(){
        var x = 1;
        return function (){
        x = x + 1;
        };
    }
    
[/code]

の無名関数部分をクロージャと呼んだりしてる所もあるようなのですが、どちらが正しいのでしょうか？

恐らく仕組みそのものを指す用語であって、関数の種類の一つとしてクロージャという名前が使われてるのは誤用だと思うのですが合っているでしょうか？


CC BY-SA 3.0
2017-10-16T00:31:19.253
38737
2019-06-29T08:38:53.143
2019-06-29T08:38:53.143
9008
3271
question
専門用語 クロージャ
クロージャーという言葉が指すのは関数自体かそれとも仕組みか


[言語仕様](https://tc39.github.io/ecma262/)においては用語として _closure_
が定義されているわけではありませんので、世界中の人が同意する「正しい」答えはありません。ただし、この言語仕様には各所でclosureの単語が出現します。たとえば:

> [14.1.21 Runtime Semantics: Evaluation](https://tc39.github.io/ecma262/#sec-
> function-definitions-runtime-semantics-evaluation)
>
> ...  
>  _FunctionExpression: function (FormalParameters) { FunctionBody }_  
>  ...  
>  3\. Let **_closure_** be FunctionCreate(Normal, FormalParameters,
> FunctionBody, scope, strict).  
>  4\. Perform MakeConstructor( ** _closure_** ).  
>  5\. Return **_closure_**.

これは関数定義の言語仕様的な表現ですが、生成される関数オブジェクトを代入する内部的な変数の名前として **_closure_**
を用いています。この事実を採用するならば、言語仕様に書いてあるclosureとは関数functionのシノニムです。

あるいは、MDNにおいては次のような説明があります:

> [Closures - JavaScript | MDN](https://developer.mozilla.org/en-
> US/docs/Web/JavaScript/Closures)
>
> A _closure_ is **_the combination_** of a function and the lexical
> environment within which that function was declared.

この定義に従えば、クロージャとは **_関数（オブジェクト）と、その関数が定義されたスコープの組み合わせ_**
です。こちらのほうがたしかに精密に言及している気がします。

ではご指摘の件はどうかというと、私は文脈によって使い分けてもいいのではないかと思います。  
私自身は言語仕様的な用法、つまり`function===closure`で使っています(笑)。  
ただ、「関数の種類の一つとしてクロージャという名前が使われてる」のは微妙ですね。クロージャである（として定義された）関数とそうでない関数を見分ける方法がない（`isClosure(f:
Function): boolean`みたいなのが作れない）のがその根拠です。


CC BY-SA 3.0
2017-10-16T03:13:05.097
38742
2017-10-16T03:13:05.097
38737
answer


意見がわかれそうな内容ではありますと前置きをしておきます。

私の認識は、クロージャは仕組みそのものであって、無名関数とは分けて考えたほうがよいと思っています。

とはいえ、PHPのマニュアルのように、

<http://php.net/manual/ja/functions.anonymous.php>

> 無名関数はクロージャとも呼ばれ、 関数名を指定せずに関数を作成できるようにするものです。

というように、無名関数 = クロージャ としている例も（言語も）見かけます。

ここで、PHPの無名関数について、もっとよく見てみると  
外の変数を参照するには以下のことをしろと書いています。

> クロージャは、変数を親のスコープから引き継ぐことができます。 引き継ぐ変数は、use で渡さなければなりません。

つまりJavaScriptでは何も意識しないでも外部の変数を参照できたのに対し、PHPでは`use`によって明示的に指定する必要があるのです。

PHPでは外部の値を参照する（この外部の値を参照できるのが、私の考えるクロージャの部分です）ためにはわざわざ別の`use`という予約語を用意していることからも、無名関数とクロージャは別として考えたほうがわかりやすいというのが私の見解です。


CC BY-SA 3.0
2017-10-16T04:07:37.720
38745
2017-10-16T04:49:16.590
2017-10-16T04:49:16.590
9008
9008
38737
answer


kenji noguchi さんが挙げている例で十分そうではありますが、回答投稿としてまとめることに意味はあると思うので、投稿しています。

クロージャーとは、プログラミング言語を実装する際に必要になるデータ構造、が私の中での第一定義だと思います。何かというと、例えば関数実行を行っている場合には、その実行環境は、おそらく以下のようなデータ構造を保持しています。

  * 各関数呼び出しスタック要素ごとに、ローカル変数 => その値 のマップ
  * グローバル変数 => その値 のマップ

ラムダ関数の問題は何かというと、それがリターンした際に、スタックは解法されるので、そこだけで保持していた変数情報は失われてしまいます。例えば、これを手っ取り早く解決しようとすると、何が起こるかというと、ラムダっぽい関数に対して、その変数のバインドはグローバル変数マップのものを利用する、だったりします。
dynamic バインディングと呼ばれ、古い言語だとこういう挙動があったりします。例: lexical binding (24.1 @ 2012 に導入！)
を on にしない場合の Emacs Lisp

しかしそれだと、こう、意図しない挙動に悩まされたりします。特に、大量のラムダを利用する関数型っぽいロジックを書く場合。

なので、もう一つの方針は、そういったラムダ関数に対して、

  * その中で参照していた外部変数 => その値

のマップを定義して、それをラムダ関数オブジェクトの内部に入れこむことです。これが、クロージャーです。

質問に対する回答としては:

  * クロージャーとは、ラムダ関数の外部参照変数を解決するための言語機能として、ラムダ関数のオブジェクトに対して外部変数情報を付与したような構造体、この構造体を指す言葉

なので、

  * 関数的なオブジェクトの一つがクロージャと呼ばれるのはあまり違和感はない
  * 同じく、言語機能の文脈で上記処理を行うことを、例えば「クロージャ処理」とか言われても、これもまたあまり違和感がない

です。


CC BY-SA 3.0
2017-10-17T02:37:19.597
38773
2017-10-17T02:37:19.597
754
38737
answer