在很久很久以前...
其實也沒有多久啦。
ES6之前宣告的方法都是用var
宣告,這也導致很多有趣的事情發生。
所以在ES6之後才導入const
跟let
這兩個宣告的方法。
當今天想要宣告一個常數,會使用const
。換而言之要宣告一個變數就會用let
。
常數跟變數的差別在於:
常數=常數就是記憶體中可以存放資料的地方,但通常不會輕易去改變常數的值。
變數=變數也是記憶體中可以存放資料的地方,而其所存放的值可以被改變。
JS當初在設定時比較隨性,所以其實可以不用宣告變數就可以拿來用。
只是如果你沒有宣告,它就會變成一個全域變數而已。
聽起來好像沒什麼大不了的,但通常不建議這麼做,客倌請小心服用啊
這會導致全域物件的污染,所以千千萬萬不要在還沒宣告變數的狀況下就拿來用!
我猜看到這邊一定會想說竟然都已經有var了,為什麼要再產生一個let呢?
既生瑜,何生亮!
因為JS在執行程式的時候會經歷兩個階段:
建立期:JS會先分配記憶體給宣告的變數及函式,其中函式又會比變數優先被宣告。
在這段期間又會分為兩個過程,(依照程式碼由上至下的順序)
註冊名稱 = JS 會宣告變數,但不會賦值給變數。
初始化 = 因為沒有值的關係,這個變數的值會是undefined。(這邊回應到上一篇文章
執行期:執行程式碼。
在執行期也會做兩件事情(依照程式碼由上至下的順序),把宣告變數裡的值指定給變數,執行函式。
過去在使用var宣告的時候會有以下這種狀況
console.log(a)
var a = 3
// 印出 undefined
// 程式碼由上開始往下讀取
// 建立期會跳過 console.log
// 建立期執行註冊名稱 var a 並初始化 var a = undefined
// 回到 console.log ,執行程式碼 undefined => 被印出
// 執行程式碼 a = 3
這種狀況也稱為變數提升(Hoisting),這也是JS才會出現的獨有狀況。
但是後來到ES6後就不會有這種狀況發生了,因為有let跟const的誕生來拯救眾生。
如果上面那段程式碼換成下面這樣:
console.log(a)
let a = 3
// 會噴錯告訴你 ReferenceError: Cannot access 'a' before initialization
差別在於用var
在宣告時變數會變成全域變數,用let
宣告時變數會變成區域變數。
JS 在初始化時會用一個 TDZ (TemporalDeadZone暫時死區) 把變數蓋住,當給予值後才能把蓋子打開。就不會有出現先預設給undfined的問題。
其實都有變數提升的設計,但多了一個TDZ的設計結果就會不一樣,因為變數儲存在記憶體的位置不同。var
沒有TDZ所以在初始化後已經被賦予undefined並儲存進記憶體中。但let跟const都是初始化後被TDZ蓋住並存進TDZ中,直到你賦予它值才可以拿出來。
上面有提到常數跟變數的差別在於值是否可以改變,接下來在做一下討論
const a = 1;
const a = 2;
console.log(a); //SyntaxError: Identifier 'a' has already been declared
//大概就是說a這個常數已經被宣告。
let b = 1;
let b = 2;
console.log(b); //SyntaxError: Identifier 'b' has already been declared
//大概就是說b這個變數已經被宣告。
修但幾勒,上面不是說變數的值可以更改嗎?你這個渣男是不是在欺騙我的感情啊!
其實如果要修改這個值要用別的方法啦!我才不是什麼愛情的騙子。來示範一下
let b = 1;
b = 2;
console.log(b); //印出2
//這樣就可以更改b這個變數的值
這幾天會在整理並在下一篇紀錄Scope chain
網頁前後端寶石庫-礦坑補完計畫系列 第 11 篇 Day 11 JavaScript var vs let (1)
const的內容是不能改變的沒錯,不過如果存的是object,那不能改變的就會變成object的記憶體位置,而不是實際的結構了。
例如
const test = [0, 1, 2, 3]
test.push(4)
console.log(test)
test = ['A', 'B']
你會看到test的結果多了 4,但是指定test為['A', 'B']會失敗。
原因是const test時,其實是在記憶體裡面作了以下事情:
[0, 1, 2, 3]
在以上例子中,真正不能修改的,是0x00這個位置中的值(0x01);但是在0x01這個位置裡面的資料是可以修改的。
因此test = ['A', 'B']
這行,會因為重新指定另一個0x02塞到0x00裡面,會報錯誤。
位置 | 資料 |
---|---|
0x00 | 0x01 (這是個const) |
0x01 | [0, 1, 2, 3] |
0x02 | ['A', 'B'] (假設會這樣指定) |
不過還是建議const的資料不要隨便修改,需要變動的資料就用let宣告。
很棒耶~
感謝大大的補充!