let实际上为 JavaScript 新增了块级作用域
用let命令声明的变量,外层代码块不受内层代码块的影响:
function f1() {
let n = 5;
var m = 5;
if (true) {
let n = 5;
var m = 10;
}
console.log(n); // 5
console.log(m); // 10
}
f1();
ES6 允许块级作用域的任意嵌套
{{{{{let insane = 'Hello World'}}}}};
//上面代码使用了一个五层的块级作用域。外层作用域无法读取内层作用域的变量
{{{{
{let insane = 'Hello World'}
console.log(insane); // 报错
}}}};
//内层作用域可以定义外层作用域的同名变量。
{{{{
let insane = 'Hello World';
{let insane = 'Hello World'}
}}}};
块级作用域的出现,在一定程度上代替了获得广泛应用的立即执行匿名函数(IIFE):
// IIFE写法
(function () {
var tmp = 3;
console.log(tmp);
}());
// 块级作用域写法
{
let tmp = 5;
console.log(tmp);
}
块级作用域与函数声明
ES5 规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。
// 情况一
if (true) {
function f() {}
}
// 情况二
try {
function f() {}
} catch(e) {
// ...
}
//上面两种函数声明,根据 ES5 的规定都是非法的。但是,浏览器没有遵守这个规定,为了兼容以前的旧代码,还是支持在块级作用域之中声明函数,因此上面两种情况实际都能运行,不会报错
ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。ES6规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。函数本身的作用域,在其所在的块级作用域之内:
function f(){
console.log('I am outside!');
}
f();
(function (){
if(false){
//重复声明一次函数f
function f(){
console.log('I am inside!');
}
}
f();
}());
上面代码在ES5中运行,会得到“I am inside!”,但是在ES6中运行,会得到“I am outside!”。这是因为ES5存在函数提升,不管会不会进入if代码块,函数声明都会提升到当前作用域的顶部,得到执行;而ES6支持块级作用域,不管会不会进入if代码块,其内部声明的函数皆不会影响到作用域的外部
注意:如果在严格模式下,函数只能在顶层作用域和函数内声明,其他情况(比如if代码块、循环代码块)的声明都会报错