今更ながらにクロージャについて少し学んだ

合ってるかは知らん

クロージャは「関数内関数」ということだけは覚えていた

馬鹿の一つ覚えというやつです。実際に手を動かしてみたらなんとなくすこしすんなりした感じがしたのでメモ

<!DOCTYPE HTML>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title></title>
<script type="text/javascript">
function out(){
  var x = 1;
  return function(){
    alert(x);
    x++;
  }
}
var f = out();
console.log(f);
f();
f();
f();
</script>
</head>
<body>
hoge
</body>
</html>

こんなhtmlがあると想像する。ちなみにコーディングはZen-Cordingでhtml:5って適当に生成したよ!

まずは実行する

alertが 1, 2, 3と出る

ステップ実行する

あれ?なんか var = x には全然アクセスしてない?

console.log(f)した

中身は

function (){
    alert(x);
    x++;
  }

これが出てきた。
つまり、returnされたもの = 関数が返ってきている = out(){}ははいってない!

ためしに変えてみた
out();
out();
out();

と直接出力してステップ実行してみる。もちろんvar x = 1;で初期化される。つーかそもそもalertしないよね。

レキシカルスコープとかスコープチェインとか

JavaScriptの変数はグローバル変数と var をつけたローカル変数があって、それらは関数内で閉じられたスコープになっているというのは理解していた。たとえば

var a = 1;

function hoge(){
  alert(a);
}
hoge(); //1

こんなんだったら関数内のaという変数がみつからない=外側のグローバルな方を見つけに行くというのは当たり前だ。
だから inn で呼ばれているものがチェインして外側の x を呼ぶのは自然なんだ!

なんとなく使い方はわかった気がする

ちゃんと理解したかは危ういけど、どうにか道具にはなれたかもしれない?

追記
function in(){}

って書いてて一回はまってた。 in はJSの予約語だった……

追記2

今考えるとたぶん var x =1; の部分は要はコンストラクタになっているんだな……と思って console.dir(f); して調べたけど f 自体にはなにも要素を保持してない。うーん、スコープチェインで out(){} の部分を見つけてやっているだけなのかなぁ……

追記3

ChromeFirefoxOperaでそれぞれステップ実行してみたけどコンストラクタになっているというよりはClosureという特別なスコープあるいはスコープチェインで解決されてるみたいだ。