es6 块级作用域的基本用法

块级作用域的概念

  根据 w3c 的规定,JavaScript 代码块是这样解释的:

  • JavaScript 语句通过代码块的形式进行组合。
  • 块由左花括号开始,由右花括号结束。
  • 块的作用是使语句序列一起执行。
  • JavaScript 函数是将语句组合在块中的典型例子。

  ES6 在这个基础上引申出来一个叫做“块级作用域”的概念,即“ {} 中间的部分是一个块级作用域”。例如:for 循环、 if 逻辑判断、while 循环等语句后面的 {} 都是一个块级作用域。

为什么需要块级作用域?

  ES5 只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景。
- 内层变量可能会覆盖外层变量。
- 用来计数的循环变量泄露为全局变量。

  1. 内层变量覆盖外层变量
var a = 'apple';

function testFn() {
    console.log(a); // undefined
    if (false) {
        var a = 'AAA'; //如果没有这一行,if语句上面的a应该输出为apple
    }
}

testFn();

//------------------

//由于ES5没有块级作用域,另外var声明的变量会产生变量提升现象,因此上面的案例等同于下面的代码
var a = 'apple';
function testFn() {
    var a;
    console.log(a); // undefined
    if (false) {
        a = 'AAA';
    }
}

testFn();
  1. 循环变量泄露为全局变量
//不存在块级作用域的var语法
for (var i = 0; i < 10; i++) {
    //handle
}

console.log(i); //10

//------------

//for循环被看作是块级作用域的let语法
for (let x = 0; x < 10; x++) {
    //handle
}
console.log(x); //Error: x is not defined

块级作用域

  块级作用域是 ES6 新增的,它对 let 命令声明的变量和 const 命令声明的常量具有较严格的规范。

  1. 没有内层变量覆盖外层变量的现象
//let命令声明的变量a
let a = 'apple';

function testFn() {
    console.log(a); // apple
    if (false) {
        let a = 'AAA';
    }
}

testFn();

//------------

//const命令声明的常量b
const b = 'banana';

function testFn2() {
    console.log(b); // banana
    if (false) {
        const b = 'AAA';
    }
}

testFn2();
  1. 不存在变量泄露为全局变量现象
//块级作用域对var命令无效,a变量泄露到外层作用域了
if (true) {
    var a = 'apple';
}
console.log(a); //apple

//let由于块级作用域的作用,不会泄露为全局变量
if (true) {
    let b = 'banana';
}
console.log(b); //Error: b is not defined

//const由于块级作用域的作用,也不会泄露为全局变量
if (true) {
    const o = 'orange';
}
console.log(o); //o is not defined
  1. 支持“{}”划分作用域的语法
{
    let a = 'apple';

    {
        let a = 'aaa';

        {
            let a = 'AAA';
        }
    }
}

  上述案例的每一对“{}”都是一个块级作用域,而且互不干扰。

  1. ES5 中的作用域

  我们知道,ES5 环境中只有全局作用域和函数作用域,那么要想实现类似块级作用域的效果,我们通常可以通过封装函数或封装匿名自调用立即执行函数来实现。例如:

//函数作用域
function testFn() {
    var a = 'apple';
}
console.log(a); //Error: a is not defined

//匿名自调用实现类似“块级作用域”的效果
;(function () {
    var b = 'banana';
})();

console.log(b); //Error: b is not defined

//es5实现多重“块级作用域”类似效果
;(function () {
    var a = 'apple';

    ;(function () {
        var a = 'aaa';

        ;(function () {
            var a = 'AAA';
        })();
    })();
})();

块级作用域与函数声明

  ES5 规定,函数只能在全局作用域和函数作用域之中声明,不能在“块级作用域”中声明。事实上,各大浏览器并没有遵守这个规则。为此,ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。在 ES6 的块级作用域之中,函数声明语句的行为类似于 let,在块级作用域之外不可引用;但又有别于 let 命令,允许重复声明同名函数且存在函数变量提升。

  块级作用域中的函数特征:

  • 允许在块级作用域内声明函数。
  • 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
  • 内层作用域声明的函数不干扰外层作用域的函数。

  a. 允许块级作用域内声明函数

if (true) {
    function testFn(){
        //handle
    }
}

  b. 同样存在函数变量提升

if (true) {
    testFn(); //这里正常输出“hehehe”,表明testFn函数变量产生提升

    function testFn() {
        console.log('hehehe')
    }
}

  c. 内层作用域声明的同名函数不干扰外层作用域的同名函数

{
    testFn(); //I am outside.

    {
        testFn(); //I am inside.

        function testFn() {
            console.log('I am inside.')
        }
    }

    function testFn() {
        console.log('I am outside.')
    }

    testFn(); //I am outside.
}

  注意: 由于 ES6 规定“块级作用域内的函数声明类似于 var 声明的变量,默认支持变量提升”,因此,下列案例直接在支持 ES6 的浏览器中运行会报错。

function testFn() {
    console.log('outside')
}

(() => {
    if (false) {
        function testFn() {
            console.log('inside')
        }
    }

    testFn(); //Error: testFn is not a function
})();

谢谢关注,欢迎点赞:)

猜你喜欢

转载自blog.csdn.net/weixin_41424247/article/details/80575465