# var、let、const 的差異?
為解決ES6以前舊版本中var宣告不夠嚴謹,同名變量覆蓋與先使用變量後定義變量仍可以輸出undefined而未報錯使除錯困難,所以產生了新的宣告方式let、const。
> ES6以前 var()
> ES6以後 let() 與 const()
## 他們是甚麼 :pencil2:
```javascript=
// 在JavaScript中宣告變數的方式,就是告訴瀏覽器我們需要一塊儲存空間(記憶體空間),並且在
// 那個空間存放指定數據。
var data = "第一週筆記"
宣告 變量名稱 = 要存的數據
```
變量名稱的一些規則
* 命名使用英文大小寫、數字、下划線或是$組成
* 名稱不能用數字當開頭
* 不能使用JS中的關鍵字語保留字
* 嚴格區分大小寫
* 使用駝峰命名
> [關於變量延伸閱讀](https://www.w3school.com.cn/js/js_variables.asp)
> [保留字](https://www.w3school.com.cn/js/js_reserved.asp)
## 先了解何謂作用域
作用域決定了這些變量的可訪問性
JavaScript中有兩種作用域
* 全局作用域
* 局部作用域
### 局部作用域
```javascript=
1.定義在{}裡面
2.有效範圍只有在定義那行到大括號結束,函式之外的所有程式碼都不能存取這個變數。
3.在局部作用域中的變量稱為局部變量
4.函數function後的{}屬於局部作用域
```
### 全局作用域
```javascript=
1.定義在{}外面
2.有效範圍在定義那行到文末,全局變量在整個程式中都可以被存取與修改。
3.在全局作用域中的變數稱為全局變量
```
**實例:**
```javascript=
// 全局作用域
var a = 1;
{
// 局部作用域
function myFunction() {
// 函數局部作用域
console.log(a);
var c = 3;
}
// 局部作用域
}
myFunction();
// a可被函式使用,因此輸出 1
// 因變量定義在函式當中c將會找不到
console.log(c);
// 輸出 Uncaught ReferenceError: d is not defined
//
// 全局作用域
```
## 關於 var :pencil2:
在ES6前宣告變量的方式,是**最弱的變數宣告**,其作用域是「函式作用域」,也就是在function 內宣告的 var,要在該 function 才有作用 ,但是如果在函式外宣告的話,其作用範圍則為 全域性。
:point_right: 特性
* 可重複定義同變量名且不會報錯
* 可以重新賦值
* 可先使用後定義(預解析),但是會輸出undefined
* 定義在全局作用域時,在整個程式中都可被存取予修改
[預解析](https://iter01.com/561971.html)
**實例:**
```javascript=
console.log(DemonSlayer);
var DemonSlayer;
// 此時未賦予任何值且先使用後定義,但是依然可以輸出undefined
var DemonSlayer = "炭治郎";
// 使用var可以重新再宣告一次同名變量
console.log(DemonSlayer);
// 賦予一個初始化的值,輸出為 炭治郎
DemonSlayer = "伊之助";
console.log(DemonSlayer);
// 給變量新的值 伊之助且輸出,可得知var可以重新賦值
```
## 關於let :pencil2:
以 let 宣告的變數,其作用域是「局部作用域」,也就是 { } 包住的區域,一但離開 { }範圍,這個變數就不會被存取到。
:point_right: 特性
* 重複定義變量名稱會有錯誤提示
* 先使用後定義會有錯誤提示
* 可以重新賦值
* 基本上用法與var相同
**實例:**
```javascript=
// console.log(DemonSlayer);
// let DemonSlayer;
// let先使用後定義,系統會提示該變量未宣告
// Uncaught ReferenceError: Cannot access 'DemonSlayer' before initialization
// 必須先定義
let DemonSlayer;
console.log(DemonSlayer);
// 未賦值 輸出undefined
// let DemonSlayer = "炭治郎";
// 使用let不可以重新再宣告一次同名變量,系統提示該變量已被宣告
// Uncaught SyntaxError: Identifier 'DemonSlayer' has already been declared
// 必須直接賦值
DemonSlayer = 炭治郎;
// 直接賦予初始化的值
console.log(DemonSlayer);
// 輸出為 炭治郎
DemonSlayer = "伊之助";
console.log(DemonSlayer);
// 給變量新的值 伊之助且輸出,可得知let也可以重新賦值
```
## 關於const :pencil2:
const 可以視為 let 的常數加強版,let 有的特性 const 都有,但 const 額外多了常數保護的特性。
在宣告 const 時就必定要指定給值,不然會產生錯誤。而且指定後不能更改賦值。
:point_right: 加強特性
* 先告要先賦值初始化,不然會報錯
* 宣告變量後就無法再修改賦予值
**實例:**
```javascript=
const IP = "110.22.XX.127";
// 恆定不動變數IP位址
const exPhone = 0957733822;
// 電話號碼
exPhone = 0912345678;
// 無法修改變量的值 系統錯誤賦值給常量變量
// Uncaught TypeError: Assignment to constant variable.
```
## 總結
| | 重複定義 | 重新賦值 | 預解析 | 區分作用域 |
| ----- | --------| -------- |---------| ------- |
| var | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | 在function時區分 |
| let | :x: | :heavy_check_mark: | :x:| :heavy_check_mark: |
| const | :x: | :x: | :x: | :heavy_check_mark:|
## 參考資料
[JavaScript 宣告: var、let、const](https://www.iware.com.tw/blog-458.html)
[[JS學徒特訓班] JavaScript ES6 : var, let, const 差異](https://codinggirl.timelog.to/a174653905)
[w3school JS 變量](https://www.w3school.com.cn/js/js_variables.asp)
[w3school JS let](https://www.w3school.com.cn/js/js_let.asp)
[w3school JS const](https://www.w3school.com.cn/js/js_const.asp)
[函式與作用域](https://eyesofkids.gitbooks.io/javascript-start-from-es6/content/part3/function_scope.html)
{"metaMigratedAt":"2023-06-16T12:15:58.911Z","metaMigratedFrom":"Content","title":"var、let、const 的差異?","breaks":true,"contributors":"[{\"id\":\"663fae2d-2bb5-4437-90b7-96f11a50e120\",\"add\":4591,\"del\":1107}]"}