块级作用域
在ES6中,使用let来代替var来声明变量,只在所在的块内有效,在块以外是找不到的
{
var a = 10;
let b = 20;
}
console.log(a); // 10
console.log(b); // b is not defined
let声明不存在变量提升
var声明的变量可以在声明的代码之前被查询到,值为undefined,而let是无法在声明和赋值以前被找到,会直接报错
var a;//js解释器会把下方的变量'a'被提到了代码最上方提前声明
console.log(a) // undefined
var a = 10;
//---------------------------------
let b;//手动写到上方 Identifier 'b' has already been declared.-标识符“ b”已被声明
console.log(b) // Cannot access 'b' before initialization.初始化前无法访问“ b”
let b = 20;
不允许重复声明
var的声明方式,是可以多次对一个变量进行声明并覆盖的,代码过多,失误会导致前面的同名变量出现问题,let就解决了这个问题,如果一个变量用let在同一个作用于内重复声明就会直接报错
var a = 10;
var a = 20;
console.log(a); //a = 20
let b = 10;
let b = 20;
Identifier 'a' has already been declared // 标识符‘a’已被声明
function fn(c){
let c; //Identifier 'c' has already been declared. 标识符‘c’已被声明
}
const声明特性
const一旦被声明,就无法再次被修改 ( 被声明同时需要立刻赋值,只声明不赋值就会报错 )
const a;//Missing initializer in const declaration.const声明中缺少初始化程序
const a = 10;
a = 20; //Assignment to constant variable.被分配到了不变的变量(常量)
const声明的对象同样不可以重复声明,直接修改常量对象,但是可以通过 对象名.对象属性 = '对象值' 进行修改和增加内部的属性和值
const person = {
name:'x'
}
person.name = 'y';
console.log(person.name) // 打印结果 name:'y'
person.age = 'y';
console.log(person)//打印结果 {name: "x", age: "y"}
//-----------------------------------------------------
const person = {
name:'x';
}
person = {
name: 'y'//Assignment to constant variable.被分配到了不变的变量(常量)
}
person = {
age: 'y'//Assignment to constant variable.被分配到了不变的变量(常量)
}
暂时性死区
在代码块儿内,使用let声明变量之前,这个变量名都是不可用的,被提前赋值就会报错,这在语法上,被称为暂时性死区(temporal dead zone,简称TDZ)
{
//TDZ开始
a = 10; //不会报错
console.log(a); //a = 10;
//TDZ结束
let a; //一旦在下方let a; 就会报错
//Cannot access 'a' before initialization(初始化前无法访问“ a”)
a = 20;
console.log(a) //a = 20;
}
为什么使用块级作用域***
原因一:内层变量会覆盖外层变量
因为var可覆盖的特性,导致内层变量可能会覆盖外层变量,用let声明,let的值就会只存在于{ }的块级作用域内,不会覆盖外部 a 的值
var a = 20;
if (1 === 1) {
var a = 40;
}
console.log(a); //打印结果 a = 40
//--------------------------------------
var a = 20;
{
let a = 40;
}
console.log(a); //打印结果 a = 20;
原因二:用来计数的循环遍历泄露为全局变量
由于var声明的变量提升导致i被声明到了循环之外,循环结束后的结果10被保留到了i,会导致循环函数出现问题
var arr = []
var i;//var变量提升,从for循环被提到了上面
for(var i = 0; i < 10; i++){
arr[i] = function(){
return i;
}
}
console.log(arr[5]());//打印结果为10
console.log(i) //打印结果为10
使用let循环以后i只存在于循环内,i不会暴露为全局变量
const arr = []
for(let i = 0; i < 10; i++){
arr[i] = function(){
return i;
}
}
console.log(arr[5]());//打印结果为5
console.log(i) //i is not defined
*用闭包的方法解决var变量提升
var arr = []
for(var i = 0; i < 10; i++){
arr[i] = (function(n){
return function(){
return n;
}
})(i)
}
原因三:不会污染全局变量
var RegExp = 10;
console.log(RegExp); //打印结果 10
console.log(window.RegExp); //打印结果 10
//------------------------------------------------
let RegExp = 10;
console.log(RegExp); //打印结果 10
console.log(window.RegExp); //打印结果 ƒ RegExp() { [native code] } √√√√√√√√√√
相同点:
- 块级作用域
- 暂时性死区
- 不可被重复声明
使用建议: 默认情况下使用const,只有在知道变量值会被修改的时候使用let声明变量