2009年10月18日日曜日

JavaScriptのクロージャ、スコープチェインについての記事

  1. JavaScriptの変数のスコープについて学ぶ
  2. JavaScriptクロージャを完全理解!スコープチェインを知る(前編)
  3. JavaScriptクロージャを完全理解!スコープチェインを知る(後編)
1.JavaScriptの変数のスコープについて学ぶからの抜粋
JavaSctiptでのグローバル変数の宣言の仕方は2種類ある。
  1. 関数本体の外で、変数宣言を行う。
  2. プログラムのいずれかの箇所で、varキーワードをつけずに変数宣言を行う
i = "global";
var j = "global";

function func() {
    k = "global";
    var l = "local"; // ローカル変数
}

上のようなコードの場合、グローバル変数は、
i, j, k, funcの4つ。
funcは、以下のコードと同等
var func = function() {
  ...
};


関数内のスコープは一つだけ!
関数内のローカル変数は、全て関数の先頭で宣言されたことになる
function test() {
   for (var i = 0; i < 10; i++) {
     // ブロック内でjを宣言
     var j = i;
   }
   // ブロックの外だが、jにはアクセスできる
   alert(j);
}


なので、以下のコードの関数fを実行すると、undefinedになる(if文の中で、vがローカル変数として宣言されているため)。
var v = "global";
function f() {
    alert(v);
    if (!v) {
      var v = "local";
    }
}

2.JavaScriptクロージャを完全理解!スコープチェインを知る(前編)からの抜粋
結論からいうと、JavaScriptにおける変数の宣言と参照とは、
「変数名をキー、変数値を値とした、ハッシュテーブルへの読み書き」である。
ハッシュテーブルとは、文字列をキーとして値を取り出せるデータ構造の事。
そして、JavaScriptのオブジェクトはハッシュテーブルと同等。

変数を宣言すると、変数名をキー、undefinedを値とするエントリが
ハッシュテーブル内に作られる。
変数に値を代入すると、ハッシュテーブル内の値が書き換わる。

以下の図における処理では、JavaScript実行環境の内部では、
目に見えないハッシュテーブルへの読み書きとして扱われる。


このハッシュテーブルの事を、正式には変数オブジェクト(Variable Object)と呼ぶ。

変数オブジェクトは場合に応じて変わる。
例えば、関数宣言の外側、<script>タグの直下で変数を宣言した場合は、
変数オブジェクトはグローバルオブジェクトと同じになります(windowオブジェクトになる)。
<script type="text/javascript">
var a = 100;  // 変数aを初期化
alert(window["a"]); // windowのプロパティを参照。100が表示される

window.a = 200; // windowのプロパティを変更
alert(a); // 変数aの値が200に変更されている
</script>

3.JavaScriptクロージャを完全理解!スコープチェインを知る(後編)からの抜粋
スコープチェインとは
実際は変数を参照するという事は、
その場における変数オブジェクト「だけ」を探す訳ではありません。
var a = 0;
function f() {
  alert(a);
}
f(); // 0が表示される

f()の中から「a」という変数を参照し、値を表示する事が出来ています。
しかし、f()のアクティベーションオブジェクト内には、「a」に対応する変数は存在しないはずですね。

つまり変数「a」は次のように探し出されたという事です。
まずf()における変数オブジェクトの中から、
「a」に対応する変数を探しますが、見つかりません。
そこで、その外側にあるグローバルオブジェクトも探す対象となり、
そこでaが見つけ出されたという訳です。

このように、変数オブジェクトを外側に向かって次々とたぐり、
参照された変数を探していくという仕組みがスコープチェインと呼ばれるものです。

クロージャとは
クロージャとは、
「関数自身が定義された環境を、ローカル変数も含めて持ち運ぶことのできる仕組み (またはそうした関数自体) 」
の事をいいます。
以下コード例。
function createCounter() {
  var n = 0;
  // クロージャを作成して返す
  return function() {
    return n++;
  };
}
// createCounter()を呼び出し、
// 戻り値 (関数オブジェクト) を変数に格納しておく
var counter = createCounter();

alert(counter()); // 0が表示される
alert(counter()); // 1が表示される
...

このようにクロージャは、
「関数呼び出しが終わってもローカル変数を参照し続けられる」
という驚くべき特徴を持っています。


この例では、戻り値となる関数が作成された瞬間に、
変数オブジェクトの連鎖(スコープチェイン)が作成されます。
そのチェインの中には、makeClosure()の変数オブジェクトも含まれており、
ローカル変数vが格納されています。


以上。

その他のシリーズは以下
JavaScriptのイロハ

0 件のコメント:

コメントを投稿


Related Posts Plugin for WordPress, Blogger...