JavaScript var let constの違い

JavaScriptでは変数を定義する際利用できるキーワードは三つあります。

* var：全バージョン利用可能
* const：ECMAScript 6以降から利用可能
* let：ECMAScript 6以降から利用可能

※ECMAScript 6は2015年6月に公開　[各バージョンの公開日はここから参照](https://ja.wikipedia.org/wiki/ECMAScript)

###var

var文は関数スコープまたはグローバルスコープの変数を宣言し、任意でそれをある値に初期化します。

```javascript
var message;    //初期化していないため [undefined]という特殊な値が設定される
var message2 = "Hello World!";

function showMessage(){
   console.info(message3);
   var message3 = "ShowMessage";
}

function showMessage2(){
   var message4;
   console.info(message4);
   message4 = "ShowMessage2";
}
showMessage();   //「undifined」が出力される
showMessage2();   //「undifined」が出力される
console.info(message);    //宣言して、値を設定されていないから「undifined」が出力される
console.info(message2);  //「Hello World!」が出力される
console.info(message3);  // 宣言されていないため、例外になる
console.info(message4);  // 宣言されていないため、例外になる
```

ちなみにvarなしで変数を宣言したら、グローバル変数になります

```javascript
function show(){
    message = "global var";
}
show();
console.info(message);   //[global var]が出力される
```
※だがこのような変数宣言はお勧めしない、厳格モードの場合、エラーになります。

```javascript
'use strict';
function show(){
    message = "global var";  //未定義のエラー
}
show();
console.info(message);   
```

####巻き上げ(hoisting)

varでは同じスコープで同じ変数を複数回宣言してもエラーにはならない、かつ変数に新たな値をセットしない限り値も変わることはない。そしてスコープ内では宣言より前から利用可能です。これが出来る原因は巻き上げにあります。

```javascript:巻き上げありのコード
console.log(hoisting);  //undefined
var hoisting;
console.log(hoisting);  //undefined
hoisting = 1;
console.log(hoisting);  //1
var hoisting;
console.log(hoisting);  //1
hoisting = 2;
console.log(hoisting);  //2
```
巻き上げの際は変数の宣言をグローバル又は関数の先頭に移動したように見える。

```javascript:巻き上げの内部から見ると
var hoisting;
var hoisting;

console.log(hoisting);  //undefined

console.log(hoisting);  //undefined
hoisting = 1;
console.log(hoisting);  //1

console.log(hoisting);  //1
hoisting = 2;
console.log(hoisting);  //2
```

気づいてないかもしれないが、関数にも巻き上げされるんです。以下のようなコードに見覚えがあると思います。

```javascript:巻き上げ前
show();  //関数が定義される前から呼び出しが出来ます
function show(){
  console.log("show message");
}
```

```javascript:巻き上げ後
function show(){
  console.log("show message");
}
show();

var tst = function(){};
var tst2 => ()
```
関数の巻き上げが変数より優先されます。

```javascript:関数の巻き上げが優先
console.log(typeof show);  // function
console.log(typeof tst1);  // undefined
console.log(typeof tst2);  // undefined
var show;
//宣言式の関数の巻き上げする
function show(){
  console.log("show message");
}
var tst1 = function(){};  //関数式は巻き上げされない
var tst2 = ()=>{};  //アロー関数も巻き上げされない
```




###let

letで宣言した変数のスコープはブロックスコープです。ブロックスコープは一番近い{}で決めるので、if、while、fuction、及び単なる{}でもlet変数のスコープになります。

```javascript
if(true){
  let a;
}
console.log(a); //ReferenceError: aが定義されていません

while(true){
  let b;
  break;
}
console.log(b); //ReferenceError: bが定義されていません

(function tst(){
  let c;
})();
console.log(c); //ReferenceError: cが定義されていません   varで宣言しても同じエラーになります

{
  let d;
}
console.log(d);//ReferenceError: dが定義されていません
```

letはvarのように同じスコープで同じ変数を複数回宣言することはできません。

```javascript
var a;
var a;

{
 let b;
 let b;  //SyntaxError: b は既に宣言されている
}
```

letの動きはループ変数に非常に似合っている、varだとループがループの外部に漏れてしまうため。

```javascript
for(var i=0;i<10;i++){}
console.log(i); // 10

for(let j=0;j<10;j++){}
console.log(j); // ReferenceError: jが定義されていません
```

厳密に言うとletで宣言した変数でも巻き上げされるのですが、一時的なデッドゾーン（temporal dead zone）によって変数が宣言される前に利用すると一律エラーになる。

###const
constはletと基本的に同じ、正しいconstでは宣言と同時に初期化しなければならない、しかも初期化した後は変更不可
```javascript
const message1; //例外
const message2 = "hello";
message2 = "hello2";//例外
```
const変数のパフォーマンスがvarとletより良いので、可能な場合はなるべくconstを使うように。

###グローバル宣言

```javascript
var firstName="first";
function tst(){
 lastName = "last";
}
tst();
console.info(window.firstName);//first
console.info(window.lastName );//last

let age=20;
console.info(window.age);//[undifined]が出力される
```
letで宣言したグローバル変数はvarのようにwindowのプロパティにはならない。

###思考

```javascript
for(var i=0;i<5;i++){
  setTimeout(()=>console.info(i),0);
}
for(var j=0;j<5;j++){
  setTimeout((m)=>console.info(m),0,j);
}
for(let k=0;k<5;k++){
  setTimeout(()=>console.info(k),0);
}
```

<details><summary>上記の三つのforループのそれぞれの出力結果と原因を考えてください</summary>
1．「5,5,5,5,5」
2．「0,1,2,3,4」
3．「0,1,2,3,4」
</details>