var、let、const的区别
var 關鍵詞
1. var聲明作用域
var定義的變量,沒有塊的概念,可以跨塊訪問, 不能跨函數訪問
function test() {var message = "hello world"; // 局部變量 } test(); console.log(message); // 報錯函數test()調用時會創建變量message并給它賦值,調用之后變量隨即被銷毀。因此,在函數test()之外調用變量message會報錯
在函數內定義變量時省略var操作符,可以創建一個全局變量
function test() {message = "hello world"; // 局部變量 } test(); console.log(message); // hello world省略掉var操作符之后,message就變成了全局變量。只要調用一次函數test(),就會定義這個變量,并且可以在函數外部訪問到。在局部作用域中定義的全局變量很難維護,不推薦這么做。在嚴格模式下,如果像這樣給未聲明的變量賦值,則會導致拋出ReferenceError。
2. var聲明提升
var在js中是支持預解析的,如下代碼不會報錯。這是因為使用var聲明的變量會自動提升到函數作用域頂部:
function foo() {console.log(age);var age = 26; } foo(); // undefinedjavaScript引擎,在代碼預編譯時,javaScript引擎會自動將所有代碼里面的var關鍵字聲明的語句都會提升到當前作用域的頂端,如下代碼:
function foo() {var age;console.log(age);age = 26; } foo(); // undefinedlet聲明
1. let聲明作用域
let定義的變量,只能在塊作用域里訪問,不能跨塊訪問,也不能跨函數訪問,而var可以跨塊訪問
// var定義的變量 if (true) {var name = 'Matt';console.log(name); // Matt } console.log(name); // Matt// let定義的變量 if (true) {let age = 26;console.log(age); // 26 } console.log(age); // ReferenceError: age沒有定義let也不允許同一個塊作用域中出現冗余聲明(重復聲明)
var name; var name;let age; let age; // SyntaxError;標識符age已經聲明過了2. 暫時性死區
let、const與var的另一個重要的區別,let、const聲明的變量不會在作用域中被提升。ES6新增的let、const關鍵字聲明的變量會產生塊級作用域,如果變量在當前作用域中被創建出來,由于此時還未完成語法綁定,所以是不能被訪問的,如果訪問就會拋出錯誤ReferenceError。因此,在這運行流程進入作用域創建變量,到變量可以被訪問之間的這一段時間,就稱之為暫時死區。
// name會被提升 console.log(name); // undefined var name = 'Matt';// age不會被提升 console.log(age); // ReferenceError:age沒有定義 let age = 26;3. 全局聲明
與var關鍵字不同,var定義的全局變量會掛載到window對象上,使用window可以訪問,而let在全局作用域中聲明的變量不會成為window對象的屬性
var name = 'Matt'; console.log(window.name); // 'Matt'let age = 26; console.log(window.age); // undefined4. for循環中的var、let聲明
for循環中var定義的迭代變量會滲透到循環體外部:
for (var i = 0; i < 5; ++i) {// 循環邏輯 } console.log(i); // 5改成使用let之后,這個問題就消失了,因為迭代變量的作用域僅限于for循環塊內部:
for (let i = 0; i < 5; ++i) {// 循環邏輯 } console.log(i); // ReferenceError: i沒有定義使用var和let定義for循環中的變量,循環里使用定時器setTimeout后循環結果如下代碼:
for (var i = 0; i < 5; ++i) {setTimeout(() => console.log(i), 0) } // 輸出5、5、5、5、5for (let i = 0; i < 5; ++i) {setTimeout(() => console.log(i), 0) } // 輸出0、1、2、3、4let 是在代碼塊內有效,var 是在全局范圍內有效。let 只能聲明一次 ,var 可以聲明多次。
當同步代碼執行完畢后,開始執行異步的setTimeout代碼,執行setTimeout時需要從當前作用域內尋找一個變量 i,for循環執行完畢,當前 i=5,執行setTimeout時輸出為5,任務隊列中的剩余4個setTimeout也依次執行,輸出為5。
變量 j 是用 let 聲明的,當前的 i 只在本輪循環中有效,每次循環的 j 其實都是一個新的變量,所以 setTimeout 定時器里面的 j 其實是不同的變量,即最后輸出0-4。
const聲明
const的行為與let基本相同,唯一一個重要的區別是:
const是用來定義常量的,而且定義的時候必須賦值,不賦值會報錯,定義之后是不允許被修改的,修改const聲明的變量會導致運行時錯誤。
const age = 26; age = 36; // TypeError: 給常量賦值// const也不允許重復聲明 const name = 'Matt'; const name = 'Nicholas'; // SyntaxError// const聲明的作用域也是塊 const name = 'Matt'; if (true) {const name = 'Nicholas'; } console.log(name); // Matt而const聲明的變量是一個對象時,修改這個對象內部的屬性并不會報錯。
這是因為const聲明的是棧區里的內容不能修改,基本數據類型的值直接在棧內存中存儲,而引用數據類型在棧區保存的是對象在堆區的地址,修改對象的屬性,不會修改對象在棧區的地址,如果重新給對象person賦值,則會報錯。
const person = {name: 'Lili' }; person.name = 'Matt'; // okJavaScript引擎會為for循環中的let聲明分別創建獨立的變量實例,雖然const變量跟let變量很相似,但是不能用const來聲明迭代變量(因為迭代變量會自增):
for (const i = 0; i < 10; ++i) {} // TypeError:給常量賦值不過,如果你只想用const聲明一個不會被修改的for循環變量,那也是可以的。也就是說,每次迭代只是創建一個新變量。這對for-of和for-in循環特別有意義:
let i = 0; for (const j = 7; i < 5; ++i) {console.log(j); } // 7, 7, 7, 7, 7 for (const key in {a: 1, b: 2}) {console.log(key); } // a, b for (const value of [1,2,3,4,5]) {console.log(value); } // 1, 2, 3, 4, 5以上內容結合《JavaScript高級程序設計(第4版)》以及自己理解所寫,歡迎大家一起來討論。
總結
以上是生活随笔為你收集整理的var、let、const的区别的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: TK-StringVar
- 下一篇: vars()函数用法
