zoukankan      html  css  js  c++  java
  • es6记录之一——块级作用域与函数声明

    函数能不能在块级作用域之中声明?这是一个相当令人混淆的问题。

    ES5 规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。

     1 // 情况一
     2 if (true) {
     3   function f() {}
     4 }
     5 
     6 // 情况二
     7 try {
     8   function f() {}
     9 } catch(e) {
    10   // ...
    11 }

    上面两种函数声明,根据 ES5 的规定都是非法的。

    但是,浏览器没有遵守这个规定,为了兼容以前的旧代码,还是支持在块级作用域之中声明函数,因此上面两种情况实际都能运行,不会报错。

    ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。

     1 function f() { console.log('I am outside!'); }
     2 
     3 (function () {
     4   if (false) {
     5     // 重复声明一次函数f
     6     function f() { console.log('I am inside!'); }
     7   }
     8 
     9   f();
    10 }());

    上面代码在 ES5 中运行,会得到“I am inside!”,因为在if内声明的函数f会被提升到函数头部,实际运行的代码如下。

    1 // ES5 环境
    2 function f() { console.log('I am outside!'); }
    3 
    4 (function () {
    5   function f() { console.log('I am inside!'); }
    6   if (false) {
    7   }
    8   f();
    9 }());

    ES6 就完全不一样了,理论上会得到“I am outside!”。因为块级作用域内声明的函数类似于let,对作用域之外没有影响。但是,如果你真的在 ES6 浏览器中运行一下上面的代码,是会报错的,这是为什么呢?

    原来,如果改变了块级作用域内声明的函数的处理规则,显然会对老代码产生很大影响。为了减轻因此产生的不兼容问题,ES6 在附录 B里面规定,浏览器的实现可以不遵守上面的规定,有自己的行为方式

    • 允许在块级作用域内声明函数。
    • 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
    • 同时,函数声明还会提升到所在的块级作用域的头部。

    注意,上面三条规则只对 ES6 的浏览器实现有效,其他环境的实现不用遵守,还是将块级作用域的函数声明当作let处理。

    根据这三条规则,在浏览器的 ES6 环境中,块级作用域内声明的函数,行为类似于var声明的变量。

    // 浏览器的 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 的浏览器中,都会报错,因为实际运行的是下面的代码。

    // 浏览器的 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';
      function f() {
        return a;
      }
    }
    
    // 函数表达式
    {
      let a = 'secret';
      let f = function () {
        return a;
      };
    }

    另外,还有一个需要注意的地方。ES6 的块级作用域允许声明函数的规则,只在使用大括号的情况下成立,如果没有使用大括号,就会报错。

    // 不报错
    'use strict';
    if (true) {
      function f() {}
    }
    
    // 报错
    'use strict';
    if (true)
      function f() {}

    (以上为ECMAScript 6 入门原文)

  • 相关阅读:
    AsyncTask(异步任务)
    Android之listview添加数据篇
    Android之ListView动态添加数据(SQLiteOpenHelper类添加数据)
    Android之sqlite数据库版本升级和降级的处理(onUpgrade和onDowngrade)
    Android中的Sqlite中的onCreate方法和onUpgrade方法的执行时机
    Android之SQLite
    Eclipse快捷键
    Android之微信布局篇
    Android之MainActivity类
    onOptionsItemSelected、onMenuItemSelected、onContextItemSelected 区别
  • 原文地址:https://www.cnblogs.com/zhengshihui/p/9747374.html
Copyright © 2011-2022 走看看