一、什么是块作用域
特点1:let,const声明的变量拥有块作用域,通常以{}作为作用域的分隔符,外层作用域无法读取内层作用域的变量
//错误
function f1() {
if (true) {
let n = 10;
}
console.log(n); // Uncaught ReferenceError: n is not defined
}
f1()
//正确
function f1() {
if (true) {
let n = 3;
console.log(n); // 3
}
}
f1()
因为n的作用域在if语句的{}中,外层作用域不可调用。
特点2:不存在“变量提升”,可能“暂时性死区”
//错误
function f1() {
console.log(a); // undefined
console.log(b); // Uncaught ReferenceError: b is not defined
var a = 1;
let b = 2;
}
f1()
//等于
function f1() {
var a;
console.log(a); // undefined
console.log(b); // Uncaught ReferenceError: b is not defined
a = 1;
let b = 2;
}
f1()
//正确
function f1() {
var a;
let b = 2;
console.log(a); // undefined
console.log(b); // 2
a = 1;
console.log(a); // 1
}
f1()
var 声明的变量,会提升到最近的非块作用域首行(变量提升),但是let变量并不具备该特性。
特点3:不允许在同一个作用域重复声明
//错误
{
let a = 2;
let a = 2;
}
//正确
let a = 2;
if (true)
{
let a = 2;
}
二、块作用域的作用
1、防止数据泄露
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
//等于
var i;
var a = [];
for (i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
var 声明的变量会发生变量提升,容易造成数据泄露,i因为“变量提升”,作用域变成“全局作用域”或“函数作用域”,改成如下代码即可。
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
注:for语句的{}是()的子作用域
2、不同块作用域声明的let变量,变量拥有独立性
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
不同的块作用域上let声明了两个i,两个i是独立的,以下代码i仅在for中let声明过一次,因此是同一个i。
for (let i = 0; i < 3; i++) {
console.log(i);
}
// 0
// 1
// 2
若是var声明的变量,则数据会发生“变量提升”,实际上是同一个变量。
for (var i = 0; i < 3; i++) {
var i = 'abc';
console.log(i);
}
// abc
//等于
var i;
for (i = 0; i < 3; i++) {
i = 'abc';
console.log(i);
}
// abc