让前端飞Web前端之路

块级作用域的理解

2020-05-05  本文已影响0人  老衲不生气

引言

由于JavaScript 存在变量提升这种特性,从而导致了很多与直觉不符的代码,这也是 JavaScript 的一个重要设计缺陷。

作用域

作用域是指在程序中定义变量的区域,该位置决定了变量的生命周期。通俗地理解,作用域就是变量与函数的可访问范围,即作用域控制着变量和函数的可见性和生命周期。

在 ES6 之前,ES 的作用域只有两种:全局作用域和函数作用域。

1、全局作用域  中的对象在代码中的任何地方都能访问,其生命周期伴随着页面的生命周期。

2、函数作用域  就是在函数内部定义的变量或者函数,并且定义的变量或者函数只能在函数内部被访问。函数执行结束之后,函数内部定义的变量会被销毁。

块级作用域就是使用一对大括号包裹的一段代码,比如函数、判断语句、循环语句,甚至单独的一个{}都可以被看作是一个块级作用域。

示例代码

简单来讲,如果一种语言支持块级作用域,那么其代码块内部定义的变量在代码块外部是访问不到的,并且等该代码块中的代码执行完成之后,代码块中定义的变量会被销毁。

变量提升所带来的问题

1. 变量容易在不被察觉的情况下被覆盖掉

2. 本应销毁的变量没有被销毁

为了解决这些问题,ES6 引入了 let 和 const 关键字,从而使 JavaScript 也能像其他语言一样拥有了块级作用域。

使用 let 关键字声明的变量是可以被改变的,而使用 const 声明的变量其值是不可以被改变的。但不管怎样,两者都可以生成块级作用域,

JavaScript 是如何支持块级作用域的

实例代码

如图,分析代码流程:

第一步是编译并创建执行上下文

刚开始的foo执行上下文

从图中可知:
1、函数内部通过 var 声明的变量,在编译阶段全都被存放到变量环境里面了。

2、通过 let 声明的变量,在编译阶段会被存放到词法环境(Lexical Environment)中。

3、在函数的作用域块内部,通过 let 声明的变量并没有被存放到词法环境中。

第二步继续执行代码,当执行到代码块里面时,变量环境中 a 的值已经被设置成了 1,词法环境中 b 的值已经被设置成了 2

执行 foo 函数内部作用域块时的执行上下文  

从图中可知:

当进入函数的作用域块时,作用域块中通过 let 声明的变量,会被存放在词法环境的一个单独的区域中,这个区域中的变量并不影响作用域块外面的变量,比如在作用域外面声明了变量 b,在该作用域块内部也声明了变量 b,当执行到作用域内部时,它们都是独立的存在。

再接下来,当执行到作用域块中的console.log(a)这行代码时,就需要在词法环境和变量环境中查找变量 a 的值了,具体查找方式是:沿着词法环境的栈顶向下查询,如果在词法环境中的某个块中查找到了,就直接返回给 JavaScript 引擎,如果没有查找到,那么继续在变量环境中查找。

执行到console.log(a)

当作用域块执行结束之后,其内部定义的变量就会从词法环境的栈顶弹出

最终执行上下文


块级作用域就是通过词法环境的栈结构来实现的,而变量提升是通过变量环境来实现,通过这两者的结合,JavaScript 引擎也就同时支持了变量提升和块级作用域了。

上一篇下一篇

猜你喜欢

热点阅读