var / let / const の違い 、巻き上げ、スコープ

#はじめに
なんとなくJavaScriptを書き初めてしまっていたので、いまさらではあるのですが var, let , constの違いについて調べました。変数だし var(iable) だろと思い込んでいたのですが、使い分けがあるということがわかりました。

#var, let, constとスコープ
以下のコードでテストしました。

```javascript:testVariable

console.log("global start"); // Break1
console.log(global_var);
var global_var = "1";
console.log(global_var);
console.log(global_let);
let global_let = "1";
console.log(global_let);
console.log(global_const);
const global_const = "1";
console.log(global_const);
console.log("global end"); // Break 2

browser.contextMenus.create({
	id: "testVariable",
	title: "test variable",
	contexts: ["all"]
})

browser.contextMenus.onClicked.addListener((info, tab) => {
	if (info.menuItemId === "testVariable") {
		console.log("onClicked start"); // Break 3
		console.log(global_var);
		console.log(global_let);
		console.log(global_const);
		console.log(in_func_var);
		console.log(in_func_let);
		console.log(in_func_const);
		testVariable();
		console.log(global_var);
		console.log(global_let);
		console.log(global_const);
		console.log(in_func_var);
		console.log(in_func_let);
		console.log(in_func_const);
		console.log("onClicked end"); // Break 6
       }
});

function testVariable() {
	console.log("testVariable start"); // Break 4
	console.log(in_func_var);
	var in_func_var = "1";
	console.log(in_func_var);
	console.log(in_func_let);
	let in_func_let = "1";
	console.log(in_func_let);
	console.log(in_func_const);
	const in_func_const = "1";
	console.log(in_func_const);
	console.log("testVariable end"); // Break 5
};
```

Break 1
![image.png](https://qiita-image-store.s3.amazonaws.com/0/262366/e8eec999-fe1f-5039-c799-25d24c08d439.png)

global_const : uninitialized
global_let : uninitialized
global_var : undefined <<< 巻き上げ

```console:console
global start background.js:31:1
undefined background.js:33:1
1 background.js:35:1
ReferenceError: can't access lexical declaration `global_let' before initialization
```
uninitilized の状態のものは Break 2 に至るまでにエラーになります。そのためエラーになる console.log はコメントにして実行

Break 2 
![image.png](https://qiita-image-store.s3.amazonaws.com/0/262366/60ed007a-3753-cc96-3ece-ecf70836d0a7.png)

global_var : 1
global_let : 1
global_const : 1

Break 3
![image.png](https://qiita-image-store.s3.amazonaws.com/0/262366/b89dd3f6-8f24-d8cc-6da6-fdbcc227a0bf.png)
global_var : 1
global_let : 1
global_const : 1
in_func_* は var, let , const 共に見られない

```console:in_func
onClicked start background.js:66:3
1 background.js:67:3
1 background.js:68:3
1 background.js:69:3
in_func_var is not defined
```
Break 4
![image.png](https://qiita-image-store.s3.amazonaws.com/0/262366/adb90588-eab0-84f8-dff9-89cd652fd0bd.png)
global_var : 1
global_let : 1
global_const : 1
in_func_var : undefined
in_func_let : uninitialized
in_func_const : uninitialized

```console:testVariable
testVariable start background.js:113:2
undefined background.js:114:2
1 background.js:116:2
can't access lexical declaration `in_func_let' before initialization
```

Break 5
![image.png](https://qiita-image-store.s3.amazonaws.com/0/262366/afbd77f8-7c5e-bbd3-dd37-c187af9a1d38.png)
global_var : 1
global_let : 1
global_const : 1
in_func_var : 1
in_func_let : 1
in_func_const : 1

このあとで ここで in_func へのアクセスエラーが起きたので、コメントアウトしました。
Break6
![image.png](https://qiita-image-store.s3.amazonaws.com/0/262366/c3cb47a0-9c99-0276-24ed-42e99a91a57a.png)

スコープ - 使っている関数内のスコープ、グローバル、let,constであれば forループもスコープ
巻き上げ - 宣言前の同じスコープで undefined でアクセスできるか。uninitializedでアクセスできずにエラーになるか。

#forループ
関数内のforループのスコープも確認しました。

```javascript:testVariable
function testVariable() {
	console.log("testVariable start");
	var in_func_var = "1";
	let in_func_let = "1";
	const in_func_const = "1";
	for (let i=1;i<3; i++) {
		console.log("for start");
		var in_for_var = "1";
		let in_for_let = "1";
		const in_for_const = "1";
		console.log("for ===");
		in_for_var = "2";
		in_for_let = "2";
		in_for_const = "2";
		console.log("for end");
	}
	console.log("testVariable end");
};
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/262366/a86c8894-a1fd-25d8-daed-68876c7c3613.png)
var は forループの中であっても 関数と同じスコープに見えます。


![image.png](https://qiita-image-store.s3.amazonaws.com/0/262366/e6716323-da77-537c-2b03-684d60eb5c3b.png)
let , const は forループの中であれば、別のスコープでした。

#let と const の代入
const は上のコードだと in_for_const = "2" のタイミングで次のエラーが出ます。

```console:const
invalid assignment to const `in_for_const'
```


#参考
[文法とデータ型 - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Grammar_and_types#Constants)
[let - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/let)
[const - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/const#Syntax)