块级作用域

原创
2017/02/17 11:56
阅读数 146

ES5 只有全局作用域和函数作用域,没有块级作用域。这会带来很多不合理的场景,比如说:

  1. 内层的变量可能会覆盖掉外层变量
    var tmp = "123";
    function f(){
     console.log(tmp);
     if(false){
       var tmp = "I m here";
     }
    }
    f();//输出是undefined,原因在于变量提升,内部的tmp变量覆盖了外部的tmp
    
    
  2. 用来计数的循环变量泄漏为全局变量
  var s = 'hello';

    for(var i = 0;i <= s.length; i++){

       console.log(s[i]);

    }

上面的代码中,i是用来控制循环的,但是循环结束之后,它并没有消失,泄漏成了全局变量。

ES6的块作用域

块级作用域与函数说明

ES5中规定,函数只能在顶层作用域和函数作用域中使用,不能在块级作用域中使用

情况一
if(true){
  function(){}
}
情况二
try{
  function (){}
}catche(e){

}

这两种情况,在ES5中都是不合法的,但是在实际的浏览器运行中,为了兼容以前的代码,还是支持在块级作用域中声明函数的,因此这两种情况实际上都可以运行。不过,严格模式下还是会报错的。

//ES5 严格模式 报错
‘use strict’
if(true){
  function f(){};
}

ES 6 引入了块级作用域,明确允许在块级作用域中声明函数

//ES6 

if(true){

  function f(){}; //不报错

}

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

function f(){console.log("I am outside");}
(function(){
  if(false){
    //重复声明一次f 
    function f(){console.log("I am inside");}
   
  }
  f();
}())

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

function f(){console.log("I am outside")};
(function(){
  function f(){console.log("I am inside")};
  if(false){};
  f();
}())

ES6的运行结果完全不一样,会得到“I am outside”.这是因为块级作用域里声明的函数类似于let,对作用域之外没有任何影响,实际运行代码如下:

function f(){console.log("I am outside")};
(function(){
  f();
}())

但是,实际上在ES6浏览器上运行这段函数的时候,是会报错的。这是为什么呢?

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

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

根据这三条规则,在浏览器的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";
  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(){};

 

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部