本节我们来学习块级作用域,ES5 中只有全局作用域和函数作用域。这会导致函数作用域覆盖了全局作用域,或者循环中的变量泄露为全局变量。

示例:

函数作用域覆盖全局作用域:

var a = 1;
function test() {
    console.log(a);  // 由于变量提升,导致内层的a变量覆盖了外层的a变量
    if (true) {
        var a  = 10;
    }
}
test();   // 输出:undefined

循环中的变量泄露为全局变量:

for(var i=0; i<5; i++) {
    console.log(i);  // 输出:0 1 2 3 4
}
console.log(i); // 输出:5

ES6的块级作用域

let 实际上为 JavaScript 新增了块级作用域,外层作用域无法获取到内层作用域,这样非常安全。即使外层和内层都使用相同变量名,也都互不干扰。

示例:

例如下面这段代码:

function test() {
    let a = 1;
    if(true){
      let a = 10;
      console.log(a);  // 输出:10
    }
    console.log(a);   // 输出:1
}

test();  // 调用函数

在函数 test()if 语句代码块中都声明了变量 a,但是因为 let 命令声明的变量只在块级作用域中起作用,所以在 if 中输出 a 的值为 10,在 test() 中输出 a 的值为 1,这两者互不干扰。

块级作用域与函数声明

ES5 中规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。而在 ES6 中引入了块级作用域,允许函数可以在块级作用域中声明。块级作用域之中,函数声明语句的行为类似于 let,在块级作用域之外不可引用。

示例:

我们来看一个例子:

{
    if(true){
        function test(){
            console.log("你好,侠课岛!")
        }
    }
}

test();

执行代码,输出结果为“你好,侠课岛!”。

但是一般考虑到兼容等问题,我们应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。

示例:

上述代码使用函数表达式来写:

{
    if(true){
        let test = function (){
            console.log("你好,侠课岛!");
        };
    }
}

除此之外,还有一个地方我们需要注意一下, ES6 的块级作用域必须有大括号,如果没有大括号,JavaScript 引擎就认为不存在块级作用域。

示例:

例如像下面这样写会报错:

// 声明函数
if (true)
    let func = function () {};

// 声明变量
if (true) let a = 1;

报错信息如下所示:

SyntaxError: Lexical declaration cannot appear in a single-statement context

上述代码中因为没有大括号,所以不存在块级作用域,不管是声明函数还是声明变量都会报错。


知否
221 声望177 粉丝

Skrike while the iron is hot.