JS中let和var的區別(良心總結!!)

前言

因爲ES6的出現,變量聲明再也不單調,除了能夠用var外,還可使用letconst安全

  • ES5: var
  • ES6: letconst

下面來了解下它們聲明的變量有哪些區別。app

1. 變量的掛載不一樣

  • var 聲明的變量會掛載在 window 上,而 let 和 const 聲明的變量不會
  • let 、const 聲明的變量會處於當前做用域中<script>
var a = 100;
console.log(window.a); // 100

let b = 100;
console.log(window.b); // undefined

const c = 100;
console.log(window.c); // undefined

console.log(b); // 100 -  當前做用域
涉及到做用域有關知識

2.有無變量提高

  • var 聲明變量存在變量提高
  • let 和 const 不存在變量提高
console.log(a);
var a = 100; // undefined =》變量提高,已聲明未賦值,默認undefined

console.log(b);
let b = 100; // Uncaught ReferenceError: Cannot access 'b' before initialization =》 未聲明使用,報錯

console.log(c);
let c = 100; // Uncaught ReferenceError: Cannot access 'b' before initialization =》 未聲明使用,報錯
能夠同時關注下【函數提高】有關概念

3.可否重複聲明

  • 同一做用域下 var 能夠聲明同名變量
  • 同一做用域下 let和const不能聲明同名變量
var a = 100;
console.log(a); // 100
var a = 10;
console.log(a); // 10

let b = 100;
let b = 10; // Uncaught SyntaxError: Identifier 'b' has already been declared

if (true) {
    let b = 10; 
    console.log(b); // 10 => 不一樣做用域內聲明能夠
}
雖然 var 能夠聲明同名變量,可是通常不會這麼使用。變量名儘量是惟一的。可關注下【JS變量命名規範】有關。

4.是否有塊級做用域

  • ES5 是沒有塊級做用域概念的,因此var聲明天然沒有
  • let 和 const 聲明造成塊級做用域
if (true) {
    var a = 100;
    let b = 10;
    const c = 10;
}
console.log(a); // 100
console.log(b); // Uncaught ReferenceError: b is not defined
console.log(c); // Uncaught ReferenceError: c is not defined
可關注 ES5 是如何模擬塊級做用域的

5. 暫時性死區

let/const 存在暫時性死區,var 沒有。下面新開標題詳解。函數

6.const聲明注意事項

  • 一旦聲明必須賦值,不能用 null 佔位
  • 聲明一個常量,聲明後不能再修改
  • 若是聲明的是複合類型數據,能夠修改其屬性
const a = 100; 

// a = 200; // Uncaught TypeError: Assignment to constant variable

const list = [];
list[0] = 10;
console.log(list);  // [10]

const obj = {a:100};
obj.name = 'apple';
obj.a = 10000;
console.log(obj);  // {a:10000,name:'apple'}

暫時性死區

只要塊級做用域內存在let命令,它所聲明的變量就「綁定」(binding)這個區域,再也不受外部的影響。code

若是在聲明變量或常量以前使用它, 會引起 ReferenceError, 這在語法上成爲 暫存性死區(temporal dead zone,簡稱 TDZ)。ip

因爲let、const沒有變量提高,才產生了 暫時性死區
if (true) {
  // TDZ開始
  tmp = 'abc'; // ReferenceError
  console.log(tmp); // ReferenceError

  let tmp; // TDZ結束
  console.log(tmp); // undefined

  tmp = 123;
  console.log(tmp); // 123
}

上面代碼中,在let命令聲明變量tmp以前,都屬於變量tmp的「死區」。內存

typeof再也不安全

在暫時性死區內,typeof 再也不是一個百分之百安全的操做作用域

typeof x; // Uncaught ReferenceError: Cannot access 'y' before initialization =》報錯:未聲明不可用
let x;

typeof undefined_variable // undefined =》未聲明的變量不會報錯

隱蔽型死區

  1. 與詞法做用域結合的暫存死區
function test() {
    var foo = 100;
    if (true) {
        let foo = (foo + 100); //  Uncaught ReferenceError: Cannot access 'foo' before initialization
    }
}
test();

在 if 語句中,foo 使用 let 進行了聲明,此時在 (foo + 100) 中使用的 foo 是 if 語句中的 foo,而不是外面的 var foo = 100;
因爲賦值運算符是將右邊的值賦予左邊,因此先執行了 (foo + 100), 因此 foo 是在還沒聲明完使用,因而拋出錯誤。it

function team(n) {
    console.log(n);

    for (let n of n.member) { // Uncaught ReferenceError: Cannot access 'n' before initialization
        console.log(n)
    }
}

team({member: ['tony', 'lucy']})

在 for 語句中,n 已經進入了塊級做用域,n.member 指向的是 let n ,跟上一例子同樣,此時 n 還未聲明完,處於暫存死區,故報錯。io

  1. switch case中case語句的做用域
switch (x) {
  case 0:
    let foo;
    break;
    
  case 1:
    let foo; // TypeError for redeclaration.
    break;
}

會報錯是由於switch中只存在一個塊級做用域, 改爲如下形式能夠避免:console

let x = 1;

switch(x) {
  case 0: {
    let foo;
    break;
  }  
  case 1: {
    let foo;
    break;
  }
}

總結

暫時性死區是一個新概念,咱們應該保持良好變量聲明習慣,儘可能避免觸發。

相關文章
相關標籤/搜索