# var、let、const 的差異 ###### tags: `Javascript` `note` 普遍來說,要分辨 **var、let 、const** 之間的差異我們會先將他們分成兩類,var 跟 let、const。 這兩類的主要差別是**作用域**,我們來看看 MDN 怎麼說明。 #### [var](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var) >The **`var` statement** declares a ***function-scoped*** or ***globally-scoped*** variable, optionally initializing it to a value. function-scoped 就是指作用在 function 內,所以離開了 function 你就沒辦法直接存取到(說沒辦法直接存取的原因是,我們可以利用 Closure 特性拿取值),而 globally-scoped 就是我們常見的最外層 ```js var a; // globally-scoped function foo(){ var b; // function scoped } ``` #### [let](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let) >The **`let`** declaration declares a ***block-scoped*** local variable, optionally initializing it to a value. 什麼是 block-scoped ?簡單說明的話就是在大括號內都是 block-scoped ,所以 function-scoped 跟 globally-scoped 也算在 block-scoped 範疇內,但經常會拿出來說明的有 for loop、while loop、if statement。 ```js for(let i = 0; i < 10; i++){ // blcok-scoped let a; } while(true){ // blcok-scoped let b } if(true){ // blcok-scoped let c; } ``` 但除了 for loop、while loop 這些,還有一種我為了讓複雜計算易於閱讀把它分區塊計算嘗試過的方法。 ```js function foo(){ // block-scoped { let a; // ... } // block-scoped { let b; // ... } } ``` 這是可以運作的,但後來因為這樣其實沒有比較好用,所以後來放棄改用一般 function,會想這樣做的原因是 Rust 帶給我的啟發,在 Rust 這可以作為一個**表達式**(expression),可以回傳值,但是 JS 不行!所以可以用 IIFE(立即函式)作代替。 ```rust fn main(){ let a = { // ... 20 }; println!("{}", a); // 20 } ``` #### [const](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const) >Constants are ***block-scoped***, much like variables declared using the [`let`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let) keyword. The value of a constant can't be changed through ***reassignment*** (i.e. by using the [assignment operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment)), and it can't be redeclared (i.e. through a [variable declaration](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#declarations)). However, if a constant is an [object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) or [array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) its properties or items can be updated or removed. const 跟 let 基本一樣,區別在於 const 不能**重新賦值**(reassignment),但是如果 const 是一個 object 或 array,可以對內部資料進行修改。 能這樣做的原因是我們並沒有對變數本身做**重新賦值**的動作,所以變數本身的**參考**(reference)並沒有變。 ```js const a = { value: 10 }; a.value = 20; console.log(a.value); // 20 const b = [0, 1]; b.push(2); // or b[0] = 4; console.log(b); // [0, 1, 2] a = 20; // ❌ reassignment b = "string"; // ❌ reassignment ``` --- ### Hoisting 我們也時常用 hoisting 來區分之間的差異,但是要知道的是 let、const 也有 hoisting,只是行為有點不同罷了,詳細可以參考 [What is hoisting](https://hackmd.io/@FizzyElt/what-is-hoisting)。