ES5规定,函数只能在顶层作用域和函数作用域(闭包)之中声明,不能在块级作用域中声明。
// 情况一
if (true) {
function f() {}
}
// 情况二
try {
function f() {}
} catch(e) {
// ...
}
上述的声明都是非法的。但是为了兼容旧的代码,上述情况实际都可以运行,不会报错。
function f() { console.log('I am outside!'); }
(function () {
if (false) {
// 重复声明一次函数f
function f() { console.log('I am inside!'); }
}
f();
}());
上例中结果会输出I am inside
,实际函数会被提升到函数作用域头部,被ES5转化为
// ES5 环境
function f() { console.log('I am outside!'); }
js
(function () {
function f() { console.log('I am inside!'); }
if (false) {
}
f();
}());
然而会在ES6环境下报错,而不是I am outside!
,原因是ES6环境中,块级作用域声明的函数,行为类似var声明的变量,实际运行代码如下:
// 浏览器的 ES6 环境
function f() { console.log('I am outside!'); }
(function () {
var f = undefined;
if (false) {
function f() { console.log('I am inside!'); }
}
f();
}());
// Uncaught TypeError: f is not a function
因此,如果一定要在块级作用域中声明函数,应该写成函数表达式,而不是函数声明语句。
// 块级作用域内部,优先使用函数表达式
{
let a = 'secret';
let f = function () {
return a;
};
}
ES6的块级作用域必须有大括号,不然JavaScript就认为不存在块级作用域
if (true) let x = 1;
// 第二种写法,不报错
if (true) {
let x = 1;
}