ES6中块级作用域

  • A+
所属分类:ES 6 JavaScript Web

ES 6 中新增加了块级作用域,解决了ES 5中由于作用域不规范引发的各类问题。

一. 概述

  1. es5作用域和es6作用域比较? 答:① ES 5中只有全局作用域和函数作用域;② ES 6 中使用let命令实际为新增了块级作用域。在不同块中使用let命令定义变量互不影响。外层不能引用let内层定义变量,内层可以引用外层变量。
  2. 函数可以在块级作用域中声明,ES5中会变量提升至函数首部,ES6中类let方式,不同域中互不影响。

二. ES 5 中作用域以及缺点

1.ES 5作用域定义

  • ES5只有全局作用域和函数作用域。
  • 使用var声明的变量会被自动添加到最接近的环境中。
  • 如果初始化时没有使用var声明,该变量会自动被添加到全局环境中。
    //全局变量
    var scope=1
    //函数中声明变量
    function  scopefun() {
      var scope=2
      console.log(scope)//2
    }
    //函数中变量不会影响到全局变量
    console.log(scope)//1
    //对象本质也是函数
    var Vehicle = function () {
      var scope=4 //4
    };
    console.log(scope)//1
    

2.ES 5作用域缺点

  • 第一种场景,内层变量可能会覆盖外层变量
    var tmp = new Date();
    
    function f() {
      console.log(tmp);
      if (false) {
        var tmp = 'hello world';
      }
    }
    //在f函数中出现了变量提升,所以不会打印外部的tmp变量
    f(); // undefined
    
  • 第二种场景,用来计数的循环变量泄露为全局变量。
    var s = 'hello';
    
    for (var i = 0; i < s.length; i++) {
      console.log(s[i]);
    }
    //变量i只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。
    console.log(i); // 5
    

三. ES 6 中块级作用域

1.ES 6块级作用域

  • 使用let命令实际为 JavaScript 新增了块级作用域。
  • 在不同块中使用let命令定义变量互不影响。
  • 外层不能引用let内层定义变量,内层可以引用外层变量。
    function f1() {
        let n = 5;
        let f = 6;
        if (true) {
          let n = 10;
          let c = 10;
          //内部引用外部变量
          console.log(f); // 6
        }
       // console.log(c); // error 内部定义外部不能使用,变为未定义变量
        console.log(n); // 5
      }
    
  • 块级作用域的出现,实际上使得获得广泛应用的匿名立即执行函数表达式(匿名 IIFE)不再必要了。
    // IIFE 写法
    (function () {
      var tmp = ...;
      ...
    }());
    
    // 块级作用域写法
    {
      let tmp = ...;
      ...
    }
    

四.块级作用域与函数声明

1.ES 5函数声明

  • ES5 规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。
  • 下面2种声明方式在ES5中都是非法的,但是浏览器在实现规范的时候为了兼容以前代码,上述声明时生效的。
    // 情况一
    if (true) {
      function f() {}
    }
    
    // 情况二
    try {
      function f() {}
    } catch(e) {
      // ...
    }
    

2.ES 6函数声明

  • ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。
  • 为了兼容旧代理,ES6 的浏览器实现可不必严格遵守以上原则。有的浏览器遵守上述规;有的浏览器,会出现函数的变量提升,并不统一。
  • 范例:
    function f() { console.log('I am outside!'); }
    
    (function () {
      if (false) {
        // 重复声明一次函数f
        function f() { console.log('I am inside!'); }
      }
    
      f();
    }());
    
  • 如上范例在es5中:
    // ES5 环境
    function f() { console.log('I am outside!'); }
    
    (function () {
      //变量提升
      function f() { console.log('I am inside!'); }
      if (false) {
      }
      f();
    }());
    
  • 如上范例在es6中:
    // 浏览器的 ES6 环境
    function f() { console.log('I am outside!'); }
    
    (function () {
      if (false) {
        // 重复声明一次函数f
        function f() { console.log('I am inside!'); }
      }
    
      f();
    }());
    // Uncaught TypeError: f is not a function
    
    //等同于如下 - >
    // 浏览器的 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
    

3.函数在块级作用域声明总结

  • 允许在块级作用域内声明函数。
  • 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
  • 同时,函数声明还会提升到所在的块级作用域的头部。
  • 上面三条规则只对 ES6 的浏览器实现有效,其他环境的实现不用遵守,还是将块级作用域的函数声明当作let处理。
  • 应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。
    // 块级作用域内部的函数声明语句,建议不要使用
    {
      let a = 'secret';
      function f() {
        return a;
      }
    }
    
    // 块级作用域内部,优先使用函数表达式
    {
      let a = 'secret';
      let f = function () {
        return a;
      };
    }
    
zhangfeng

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: