还有人不知道let,var和const 有什么区别吗?

218 阅读4分钟

let,var和const 有什么区别?

1、作用域不同

let和const是块级作用域,var是函数作用域,花括号{}就是块级作用域,函数作用域就是只能在函数里面使用。 下面是一些例子:

(1)变量 a 用 let 声明,是块级作用域,在{}外未声明,所以使用时会报错

{
  let a = 0;
}
console.log(a); // ReferenceError: a is not defined

(2) 变量 b 用 let 声明,是块级作用域,可以在{}内声明后使用

{
  let b = 0;
  console.log(b); // 0
}

(3) 变量 c 用 var 声明,是函数作用域,可以在{}外使用。第一个 c 时变量还未赋值,所以打印 undefined,第二个 c 变量赋值 0,所以打印的 0

console.log(c); // undefined
{
    var c = 0;
}
console.log(c); // 0

暂时性死区:

如果区块中使用 let 和 const 命令声明变量,这个区块就会对这些命令声明的变量形成封闭的作用域。在变量被声明之前使用这些变量,就会报错,这就是暂时性死区。

console.log(person); // ReferenceError: Cannot access 'person' before initialization
let person = 'a'; 

块级作用域解决了ES5中的两个问题:

(1)内层变量可能覆盖外层变量

使用 var 赋值时,在{}外给 a 赋值为0,在{}内给 a 赋值为1,可以看到最终内层的 1 覆盖了外层 a 赋值的 0

var a = 0;
{
  var a = 1;
}
console.log(a); // 1

使用 let 赋值时,由于 let 是块级作用域,所以 {} 内的变量 a 不会影响 {} 外的变量 a ,这是两个完全独立的变量

let a = 0;
{
  let a = 1;
  console.log(a); // 1
}
console.log(a); // 0

(2)用来计数的循环变量泄露为全局变量

可以看到使用 let定义的变量 i 在 for 循环外不能访问,但是使用 var 定义的变量 i,在 for 循环外还能继续访问。

let arr = [1, 2, 3, 4, 5];
for (let i = 0; i < arr.length; i++) {};
console.log(i);  // 报错:i is not defined

for (var i = 0; i < arr.length; i++) {};
console.log(i);  // 5,泄露为全局变量

2、变量提升

var存在变量提升(将变量声明提升到当前作用域的顶部),let和const不存在变量提升,所以 let 和 const 变量只能在声明之后使用,否则会报错。

(1)使用 var 声明变量 b,由于变量声明被提升,所以访问不会报错,只是没有赋值,所以输出的是 undefined

console.log('b', b); // b undefined
var b = 2;

(2)使用 let 和 const 声明变量,不存在变量提升,所以不能在声明之前使用,会报错

console.log('a', a); // ReferenceError:Cannot access 'a' before initialization
let a = 1;
console.log('c', c); // ReferenceError:Cannot access 'a' before initialization
const c = 3;

3、常量与变量

const 声明的值是常量,赋值后就不可以修改,但是并不是值不能改动,而是值指向的那个内存地址不能改动,而 let 和 var 声明的变量值可以被修改。

(1)对于基本类型的数据(Number、String等),其值就保存在变量指向的那个内存地址,因此不能修改。如下:

使用 const 声明变量 person,初值为 a 字符串,将 person 的值修改成 b 时会报错

const person = 'a'
person = 'b'; // TypeError: Assignment to constant variable.  赋值失败

(2)对于引用类型的数据(Object、Array)来说,变量指向数据的内存地址,保存的只是一个指针,const只能保证这个指针是固定不变的,至于它指向的数据结构是不是可变的,就完全不能控制了。如下:

使用 const 声明变量 person,初值为一个对象,对象中包含属性 name,值为 a 字符串,将 person.name 的值修改成 b,再添加一个属性person.age,可以看到输出值 person 已被修改成功

const person = {
  name: 'a'
};
person.name = 'b';
person.age = 12;
console.log(person); // { name: 'b', age: 12 } 

4、给全局添加属性

在全局作用域中用var声明的变量为全局变量,并且能用全局对象访问,但是let和const不行。(浏览器的全局对象是window,Node的全局对象是global)

var a = '111';
window.a // '111'

let b = 2;
window.b // undefined

5、重复声明

var声明变量时,可以重复声明变量,后声明的同名变量会覆盖之前声明的变量,const和let不允许重复声明变量,重复声明会报错。

var a = 0;
var a = 'aaa'; // a 被覆盖
console.log(a); // aaa

let a = 0;
let a = 'aaa';
console.log(a); // SyntaxError: Identifier 'a' has already been declared

6、初始值

在声明时,var 和 let 可以不用设置初始值,而且const声明变量必须设置初始值,且不能使用null占位

(1)let 和 var 声明的变量可以不设置初值,输出是 undefined

let a; 
console.log('a', a); // a undefined
var a; 
console.log('a', a); // a undefined

(2)const 声明的变量不设置初值会报错

const a;  // SyntaxError: Missing initializer in const declaration