ES6 let和const的区别

1.ES6 新增了let命令,用来声明变量。它的用法类似于var。 const声明一个只读的常量。一旦声明,常量的值就不能改变。

let:声明的是变量

一、不存在变量提升


var命令会发生“变量提升”现象,即变量可以在声明之前使用,值为undefined。这里就不详细说这个东西,有需要的可以看我 详解 javascript 变量提升 这个文章。

为了纠正这种现象,let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。

// var 的情况
alert(foo); // 输出undefined
var foo = 2;

// let 的情况
alert(bar); // 报错ReferenceError
let bar = 2;

上面代码中,变量foo用var命令声明,会发生变量提升,即脚本开始运行时,变量foo已经存在了,但是没有值,所以会输出undefined。变量bar用let命令声明,不会发生变量提升。这表示在声明它之前,变量bar是不存在的,这时如果用到它,就会抛出一个错误

二、暂时性死区,先声明在使用


使用let命令声明变量之前,该变量都是不可用的。

var num = 123;

if (true) {
num = 'abc'; // ReferenceError
let num;
}

三、不允许重复声明


let不允许在相同作用域内,重复声明同一个变量。

// 报错
function fn() {
let a = 10;
var a = 5;
}

// 报错
function fn() {
let a = 10;
let a = 5;
}

四、块级作用域


ES5 只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景。

第一种场景,内层变量可能会覆盖外层变量。

var tmp = '你好';
function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';
}
}
f(); // undefined
上面代码的原意是,if代码块的外部使用外层的tmp变量,内部使用内层的tmp变量。但是,函数f执行后,输出结果为undefined,原因在于变量提升,导致内层的tmp变量覆盖了外层的tmp变量。

ES6的块级作用域,let实际上为javascript新增的块级作用域。

function f1() {
let n = 20;
if (true) {
let n = 10;
}
console.log(n); // 20
}
上面的函数有两个代码块,都声明了变量n,运行后输出 20。这表示外层代码块不受内层代码块的影响。如果两次都使用var定义变量n,最后输出的值才是 10。

const:常量

const声明一个只读的常量。一旦声明,常量的值就不能改变。
const PI = 3.1415;
PI // 3.1415

PI = 3;
// TypeError: Assignment to constant variable.
上面代码表明改变常量的值会报错。

const的作用域与let命令相同:只在声明所在的块级作用域内有效
const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
const声明的常量,也与let一样不可重复声明。
const foo = {};

// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123

// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only
上面代码中,常量foo储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把foo指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。

let和const的相同点:
只在声明所在的块级作用域内有效。
不会产生提升,同时存在暂时性死区,只能在声明的位置后面使用。
不可重复声明。
let和const的不同点:
let声明的变量可以改变,值和类型都可以改变;const声明的常量不可以改变,这意味着,const一旦声明,就必须立即初始化,不能以后再赋值
数组和对象等复合类型的变量,变量名不指向数据,而是指向数据所在的地址。const只保证变量名指向的地址不变,并不保证该地址的数据不变,所以将一个复合类型的变量声明为常量必须非常小心。

特点有三:

  • 变量生命提升
  • 可重复定义同一个名字的变量不报错
  • 全局变量挂载到window

let和const的特性:

  • 没有变量生命提升
  • 不能重复声明同一个变量,即使是var过的变量,甚至是行参也不行。
  • 声明的变量不会挂载到window上
  • 有块级作用域的特点
  • 在大括号{}里边会形成临时死区
  • 可解决闭包问题。
  • [const特殊] var和let定义变量,const定义常量

console.log(a) //undefined a 变量提升到前面,相当于 var a
var a=10;

这里曾经出现过一个笑话

console.log(name)//10
var name=10
//这里我毫不犹豫想的肯定是undefined ,其实打印的是10,因为name是JavaScript内置的对象。
//name不是关键字,是window下自有的属性。所以一般不会用name当做变量名使用

let 和 const 声明的变量没有变量提升。

console.log(a);//报错 Cannot access 'a' before initialization
//变量无法提升;
let a = 10;

console.log(b);//报错 Cannot access 'b' before initialization
//变量无法提升;
const b = 10;

var 能重复声明。

var a = 10;
var a = 20;
console.log(a)//20

let 和 const 不能重复声明。

let a = 10;
let a = 20;//报错Uncaught SyntaxError: Identifier 'a' has already been declared

const b = 10;
const b = 20;//报错 'b' has already been declared

var 和 let 声明时可以不用设置初始值。

var a,let b;
a = 10;
b = 20;
console.log(a,b)//10,20

const 声明时必须设置初始值,不能使用 null 占位。

const a;
a = 20;//报错 Missing initializer in const declaration

var 没有块级作用域

for(var i=0;i<3;i++){
console.log(i);//0,1,2
}
console.log(i);//3,没有块级作用域,外层也能访问

if(true){
var a = 10;
}
console.log(a);//10

let 和 const 有块级作用域

for(let i=0;i<3;i++){
console.log(i);//0,1,2
}
console.log(i);//报错 i is not defined,有块级作用域,外层不能访问

if(true){
let a = 10;
}
console.log(a);//报错 a is not defined

if(true){
const b = 10;
}
console.log(b);//报错 b is not defined

var 不存在暂时性死区

var a = 10;
if(true){
console.log(a);//10
var a = 20;
}

let 和 const 存在暂时性死区

var a = 10;
if(true){
console.log(a);//报错 Cannot access 'a' before initialization
let a = 20;
}

var b = 10;
if(true){
console.log(b);//报错 Cannot access 'b' before initialization
const b = 20;
}

常见面试题

function sayHi() {
console.log(name)
console.log(age)
var name = 'Lydia'
let age = 21
}

sayHi() //undefined 和 ReferenceError

for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1)
}

for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1)
}

// 0 1 2 和 3 3 3


推荐 收藏
评论(0) 阅读(304)
刷新评论 返回顶部
May最新博客