let 和 const 是 ES6 中新增的命令,是用于解决 ES5 中使用 var 命令声明变量的一些问题而出现的,看一下 var 命令的一些不合理的问题。
var主要有如下几个不合理的地方:
没有块级作用域
重复声明
绑定全局作用域
变量提升
问题1:没有块级作用域
ES5 只有全局作用域和函数作用域,没有块级作用域。在ES6之前,最常见的修复方法是使用IIFE(Immediately Invoked Function Expression,意为立即调用的函数表达式,即声明函数的同时立即调用这个函数)。
eg:
for(var i=0;i<5;i++){
setTimeout(function(){
console.log(i);
},1000)
} //5555
IIFE解决
for (var i = 0; i < 5; i++) {
(function(i) {
setTimeout(function() {
console.log(i);
}, 1000);
})(i);
}//01234
但是let和const的发明让我们有了一种更简单的修复方法。
不仅是在循环里引入了一个新的变量环境,而且还是针对每次迭代都会创建这样一个新作用域。 这就是我们在使用立即执行的函数表达式时做的事
let解决
for(let i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, 1000)
}
问题2:重复声明
var可以反复声明相同标识符的变量,在大多数语言中,在同一个作用域多次声明同一个变量是非法的,但是在 ES5 中使用 var 命令重复声明的没有任何问题的;而let是不允许的;
eg:
var a = 1;console.log(a); //1
var a = 2;
console.log(a); // 2
var a = 3;
console.log(a); //3
问题3:绑定全局作用域
在全局作用域下通过 var 命令声明变量,会创建一个新的全局变量作为全局对象的属性
eg:
`````var a = 1;
console.log(window)
问题4:变量提升
变量提升指的是变量声明的提升,不会提升变量的初始化和赋值,JavaScript会把作用域里的所有变量和函数提到函数的顶部声明
eg:
console.log(foo) //undifined
var foo = 123
foo其实已经在调用前被声明了,只是没有被初始化。
对于let来说,情况有点不同:
eg:
console.log(aLet)
// Uncaught ReferenceError: Cannot access 'aLet' before initialization
let aLet = 2
注:在let/const声明之前就访问对应的变量与常量,会抛出ReferenceError错误;但在var声明之前就访问对应的变量,则会得到undefined
根据ES6标准中对于let/const声明的章节13.3.1,说由let/const声明的变量,当它们包含的词法环境(Lexical Environment)被实例化时会被创建,但只有在变量(et/const)的词法绑定(LexicalBinding)已经被求值运算后(初始化),才能够被访问。
当程序的控制流程在新的作用域(module, function或block作用域)进行实例化时,在此作用域中的用let/const声明的变量会先在作用域中被创建出来,但因此时还未进行词法绑定,也就是对声明语句进行求值运算,所以是不能被访问的,访问就会抛出错误。所以在这运行流程一进入作用域创建变量,到变量开始可被访问之间的一段时间,就称之为TDZ(暂时死区)。
TDZ最一开始是为了const所设计的,但后来的对let的设计也是一致的。
以上面解说来看,以let/const声明的变量,也是会有提升(hoist)的作用。提升是JS语言中对于变量声明的基本特性,只是因为TDZ的作用,并不会像使用var来声明变量,只是会得到undefined而已,现在则是会直接抛出ReferenceError错误,而且很明显的这是一个在运行期间才会出现的错误。
eg:
let x = 'outer value'
(function () {
// 这里会产生 TDZ for x
console.log(x) // TDZ期间访问,产生ReferenceError错误
let x = 'inner value' // 对x的声明语句,这里结束 TDZ for x
}())
在例子中的IIFE里的函数作用域,变量x在作用域中会先被提升到函数区域中的最上面,但这时会产生TDZ,如果在程序流程还未运行到x的声明语句时,算是在TDZ作用的期间,这时候访问x的值,就会抛出ReferenceError错误。
特点
1.const一般只用于声明常量,声明的同时立即初始化(Missing initializer in const declaration语法错误)
eg:
const y; // Missing initializer in const declaration
2.声明的常量不能修改,否则会报错(Assignment to constant variable.(指定恒定变量。))
注:声明对象、数组(引用类型数据)的时候,对象的属性名和属性值都可以添加、修改,保证变量名指向的地址不变;不能重新指向另一个对象,不能重写对象。
eg:
const x = 1;
x = 2; // Uncaught TypeError: Assignment to constant()
const obj = {
name: 1
}
obj.name = 2;
obj.name1 = 3;
console.log(obj) //{name: 2, name1: 3}
obj = { name: 3 } // Assignment to constant variable.
3.块级作用域
eg:
{
const age = 17;
}
age; //ReferenceError: age is not defined
** 4.存在暂时性死区,只能在声明之后调用**
1.1
let a;
const a
结果:
let a; // 不报错
const a // 报错 Missing initializer in const declaration
1.2
let user = {name:'Lucy',age:17};
const USER_INFO = user;
console.log(user)
console.log(USER_INFO)
user.age = 32;
console.log(user)
console.log(USER_INFO)
结果:
{name:‘Lucy’,age:17}
{name:‘Lucy’,age:17}
{name:‘Lucy’,age:32}
{name:‘Lucy’,age:32}
1.3
let a = 'aaa';
console.log(a);
console.log(window.a);
var b = 'bbb';
console.log(b);
console.log(window.b);
c = 'ccc';
console.log(c);
console.log(window.c);
结果:
aaa
undefined
bbb
bbb
ccc
ccc
1.4
var a = 1;
b = 2;
delete a;
delete b;
console.log(window)
结果:
delete a; //使用var定义的变量,无法删除。原因:使用var语句添加的window属性有一个名为configurable的特性,其值被设置为false。
delete b;// 删除
delete window.c;// 删除
1.5
for (var i = 0; i < 3; i++) {
console.log(i)
}
console.log(i)
for (let j = 0; j < 3; j++) {
console.log(j)
}
console.log(j)
结果:
0 1 2
3
0 1 2
j is not defined
1.6
for (var i = 0; i < 3; i++) {
let i = 'bbb';
console.log(i);
}
for (let j = 0; j < 3; j++) {
var j = 'aaa';
console.log(j);
}
结果:
bbb
bbb
bbb
Identifier ‘j’ has already been declared.(已声明标识符“i”)
1.7
var a = [];
for (var i = 0; i < 10; i++) {
console.log(i);
a[i] = function () {
console.log(i); //执行此代码时,for循环已经执行完毕,i 的值是10
};
}
a[6]();
结果:
0 1 2 3 4 5 6 7 8 9
10
1.8
for (var i = 1; i <= 5; i++) {
(function() {
setTimeout( function timer() {
console.log(i);
},i*1000 );
})();
}
结果:
66666
相关面试题链接:
https://blog.csdn.net/qq_37024887/article/details/106784068