ES6 块级作用域解决的一些问题
ES6 块级作用域解决的一些问题
博客说明
文章所涉及的资料来自互联网整理和个人总结,意在于个人学习和经验汇总,如有什么地方侵权,请联系本人删除,谢谢!
简介
在ES5
中没有块级作用域,这出现了许多的问题,ES6
中新增了块级作用域
问题一:内层变量覆盖外层变量
由于使用var
声明的变量,存在变量提升,在内层的tmp
会覆盖掉外层的tmp
变量
var tmp = 'hahaha';
function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';
}
}
f(); // undefined
问题二:在for循环中的循环变量泄漏为全局变量
在使用for
循环时,i变量在循环结束之后并没有回收,而是泄漏成了全局变量
var s = 'hahaha';
for (var i = 0; i < s.length; i++) {
console.log(s[i]);
}
console.log(i); // 6
ES6的块级别作用域
let
和const
为JavaScript新增了块级作用域
在同一个块级里面,外层代码块不受内层代码块的影响
function f1() {
let n = 5;
if (true) {
let n = 10;
}
console.log(n); // 5
}
函数声明
ES5
规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。但是,浏览器没有遵守这个规定,为了兼容以前的旧代码,还是支持在块级作用域之中声明函数,因此上面两种情况实际都能运行,不会报错。
像以下的代码,在ES5
中是非法的,但是在浏览器中不会报错的
// 情况一
if (true) {
function f() {}
}
// 情况二
try {
function f() {}
} catch(e) {
// ...
}
虽然不报错,但是ES6还是解决了这个问题,ES6
引入了块级作用域,明确允许在块级作用域之中声明函数。
ES6
规定,块级作用域之中,函数声明语句的行为类似于let
,在块级作用域之外不可引用。
但是这样改动对老代码十分不友好,为了减轻因此产生的不兼容问题,ES6 在附录 B里面规定,浏览器的实现可以不遵守上面的规定,有自己的行为方式。
- 允许在块级作用域内声明函数。
- 函数声明类似于
var
,即会提升到全局作用域或函数作用域的头部。 - 同时,函数声明还会提升到所在的块级作用域的头部。
注意,上面三条规则只对 ES6 的浏览器实现有效,其他环境的实现不用遵守,还是将块级作用域的函数声明当作let
处理。
函数表达式和函数声明
考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。
// 块级作用域内部的函数声明语句,建议不要使用
{
let a = 'secret';
function f() {
return a;
}
}
// 块级作用域内部,优先使用函数表达式
{
let a = 'secret';
let f = function () {
return a;
};
}
作用域的标识
ES6
的块级作用域必须有大括号,也就是标识,如果没有大括号,JavaScript 引擎就认为不存在块级作用域。
if (true) let x = 1; // 报错
if (true) {
let x = 1;
}
// 不报错
感谢
万能的网络
菜鸟教程
阮一峰的es6语法教程