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;
  }
}

总结

暂时性死区是一个新概念,咱们应该保持良好变量声明习惯,尽可能避免触发。

相关文章
相关标签/搜索