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的块级别作用域

letconst为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语法教程

以及勤劳的自己,个人博客GitHub

微信公众号

上一篇 下一篇