scope

作用域

作用域决定了一段代码能访问到那些数据,这些数据保存在词法环境对象中
变量与函数的作用范围,控制着变量与函数的可见性与声明周期

es6 之前只有全局作用域与函数作用域。

块级作用域

为了解决变量提升带来的覆盖与污染问题,出现了块级作用域 const、let

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function foo(){
var a = 1
let b = 2
{
let b = 3
var c = 4
let d = 5
console.log(a)
console.log(b)
}
console.log(b)
console.log(c)
console.log(d)
}
foo()

1.函数内部通过 var 声明的变量,在编译阶段全都被存放到变量环境里面了。
2.通过 let 声明的变量,在编译阶段会被存放到词法环境(Lexical Environment)中。
3.在函数的作用域块内部,通过 let 声明的变量并没有被存放到词法环境中

执行这个作用域块的时候,作用域块中通过 let 声明的变量,会被存放在词法环境的一个单独的区域中
其实,在词法环境内部,维护了一个小型栈结构,栈底是函数最外层的变量,进入一个作用域块后,就会把该作用域块内部的变量压到栈顶;当作用域执行完成之后,该作用域的信息就会从栈顶弹出,这就是词法环境的结构。需要注意下,我这里所讲的变量是指通过 let 或者 const 声明的变量
当执行到作用域块中的console.log(a)这行代码时,就需要在词法环境和变量环境中查找变量 a 的值了,具体查找方式是:沿着词法环境的栈顶向下查询,如果在词法环境中的某个块中查找到了,就直接返回给 JavaScript 引擎,如果没有查找到,那么继续在变量环境中查找。

变量提升与块级作用域的提升

变量环境实现函数级作用域:
执行一个函数时,会创建一个执行上下文,其中的变量环境会保存该函数代码内生成的变量

块级作用域通过词法环境的栈结构实现

执行时机

函数只会在第一次执行的时候被编译,所以编译时变量环境和词法环境最顶层数据已经确定了。

当执行到块级作用域的时候,块级作用域中通过let和const申明的变量会被追加到词法环境中,当这个块执行结束之后,追加到词法作用域的内容又会销毁掉。

参考:
https://www.jianshu.com/p/0fcc26e13300

思考

1.函数级作用域如何实现?
2.块级作用域又是如何实现的?


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!