JavaScriptにおけるスコープとクロージャ

##グローバルスコープ
###グローバルオブジェクト
グローバル変数やグローバルプロパティ、グローバルオブジェクトは、異なるスコープからでもアクセスすることができる。

JavaScriptにおいて、グローバルスコープで変数や関数を定義するとき、JavaScriptで元々定義されているwindowオブジェクトのプロパティやメソッドとして扱われる。

```js
var myString = 'abc';
var myFunction = function(){};
console.log('myString' in window); //出力: true
console.log('myFunction' in window); //出力: true
```
###グローバル関数

グローバル関数はどこからでも呼び出すことができる。

・decodeURI(encodeURI) - 引数として渡したURLエンコードされた文字列をデコードし、その文字列を返す。encodeURI()でエンコードされる文字のみがデコードされる。

・decodeURIComponent(encodeURI) - 引数として渡したURLエンコードされた文字列をデコードし、その文字列を返す。encodeURIComponent()でエンコードされる文字のみがデコードされる。

・encodeURI(uri) - 引数として渡した文字列にURLエンコードを行い、その文字列を返す。ただし、英数字といくつかの記号文字のエンコードは行わない。

・encodeURIComponent(uriComponent) - 引数として渡した文字列にURLエンコードを行い、その文字列を返す。ただし、英数字といくつかの記号文字のエンコードは行わない。

・eval(x) - 引数として渡した文字列をJavaScriptとして実行する。セキュリティホールとなりうるため、利用は推奨されない。

・isFinite(number) - 引数として渡した数値が実数かどうかを評価し、trueもしくはfalseを返す。引数には関数実行前にNumber()と同等の変換が行われる。

・isNaN(number) - 引数として渡した数値がNaNかどうか評価し、trueもしくはfalseを返す。引数には関数実行前にNumber()と同等の変換が行われる。そのため、実際には数ではないもの(true,null.'',' 'など)もfalseとして判定してしまう。

・parseFloat(string) - 引数として渡した文字列を数値に変換する。Number()とは文字列の変換方法が異なる。

・parseInt(string, radix) - strに渡した文字列を、radixに渡した底の値をもとに整数値に変換する。Number()とは文字列の変換方法が異なる。

###グローバル変数とグローバルプロパティの違い
グローバル変数はvar演算子を使って定義されるもので、グローバルプロパティはvarを使わないで定義される。グローバルプロパティはdeleteで削除可能だがグローバル変数はdeleteで削除することができない。

確認用コード

```js
var a = 10; //グローバル変数
b = 100; //グローバルプロパティ

delete a; //グローバル変数はdeleteで消去できない
delete b; //グローバルプロパティはここで削除される

console.log(a); //10
console.log(b); //bは削除されたのでエラーとなる

```
グローバル変数は関数外で定義するが、グローバルプロパティは、どのスコープからでも定義することができる。いいかえると、関数内でvarを使わずに定義したものはグローバルプロパティ扱いとなる。

```js
var foo = function(){
    var bar1 = 'a'; //関数内スコープ
    bar2 = 'b'; //グローバルプロパティ
}();

try{
  console.log(bar1);
} catch(e) {
  console.log("Can't access bar1"); //関数内スコープの変数はアクセスできない
}

try{
  console.log(bar2);
} catch(e) {
  console.log("Can't access bar2"); //グローバルプロパティは異なるスコープでもアクセス可能
}

```

関数内で変数を定義するときは、必ずvarを使うべきである。


##スコープチェーン（静的スコープ）とクロージャ

JavaScriptは変数を参照するときに、同じ関数内に目的の変数が定義されていないかを探す。見つからなかった場合、今度は親関数の中を探す。それでも見つからない場合はさらに親の関数内を探し、最終的にはグローバルスコープまで探しにいく。最後に見つからなかった場合は、undefinedを返す。
このように変数を参照することを、"スコープチェーンをたどる"という。スコープチェーンの検索は最初に発見した値を返す。したがって同じ名前をもった変数がスコープチェーンの上位にあっても、その変数が参照されることはない。（これをマスキングという）

クロージャとは「スコープチェーンに存在する変数への参照を保持している関数」である
クロージャの例を以下に示す

```js
var countUpFromZero = function(){
  var count = 0;
  return function(){
    return ++count;
  };
}();

console.log(countUpFromZero());
console.log(countUpFromZero());
console.log(countUpFromZero());

```


クロージャは値ではなく参照を保持している。以下の例では、1 2 3と出力したいのだが失敗している。

```js

var logElementNumber = function() {
  var funcArray = [];
  var i;
  for(i = 0; i < 3; i++){
    funcArray[i] = function(){ //クロージャ
      console.log(i);
    }
  }
  return funcArray;
}();

logElementNumber[0](); //出力 3　3回目のi++でiの値が3になる。クロージャのiは変わりゆくiを常に参照している。
logElementNumber[1](); //出力 3
logElementNumber[2](); //出力 3

```


クロージャを使わずに実装

```js

var logElementNumber = function() {
  var funcArray = [];

  var func = function(n){
    return function(){
      console.log(n);
    };
  };

  for (i = 0; i < 3; i++) {
    funcArray[i] = func(i);
  }
  return funcArray;
}();

logElementNumber[0](); //出力 0　
logElementNumber[1](); //出力 1
logElementNumber[2](); //出力 2

```

以下の例では、nは値が代入されているのに対しiは参照を渡しているのを確認することができる

```js

var logElementNumber = function(len){
  var funcArray = [];
  var i;
  var func = function(n) {
    return function(){
      console.log(n, i);//この場合は、nがこの関数のスコープでiが親関数のスコープ
    };
  };
  for(i = 0; i < len; i++){
    funcArray[i] = func(i);
  }
  return funcArray;
};//即時実行を行わない

var myArray1 = logElementNumber(3);
var myArray2 = logElementNumber(5);

myArray1[1]();//出力：1 3
myArray1[2]();//出力：2 3
myArray2[1]();//出力：1 5
myArray2[2]();//出力：2 5

```

ほかにjavascriptの仕様として重要なものがある。スコープチェーンは関数実行時ではなく関数定義時に決められるということだ。以下はグローバルスコープで宣言されているクロージャ関数だ。

```js
var a = 1;
var func = function(){ console.log(a)};

(function(f){
   var a = 100;
   f();
})(func);

```
##リファレンス
開眼！Javascript（第５章，第７章）