在js中,函数存在一个隐式属性[[Scopes]],这个属性是用来保存当前函数的执行上下文环境,也是VO的一个集合,由于在数据结构上是链式的,因此也被称作是函数作用域链,我们可以把它理解为一个数组,可以理解为一系列的AO对象所组成的一个链式结构。
对于 AO 不清楚的同学,我也整理了一篇简易的文档,可以点击AO 或者移步主页查看。
function foo(){}
console.dir(foo)
- 当函数被调用后
function foo(){
console.dir(foo)
}
foo()
通过给 console.dir(foo)这一行代码打断点就可以清晰的看到 scope 下面分别有 local 和 global
因此,我们可以得出一个结论:[[scopes]]属性在函数声明时产生,在函数调用时更新,在函数调用时,将该函数的AO对象压入到[[scopes]]中。
作用域链的作用
作用域链的作用是保证执行环境里面的有权访问的变量和函数是有序的,作用域的变量只能向上访问,变量对象访问到 window 对象即被终止,作用域链向下访问是不被允许的。
最直观的变现就是:
函数内部可以访问函数外部声明的变量
var a = 4
function foo(){
console.log(a)
}
foo() // 4
函数外部不可以访问函数内部声明的变量
function foo(){
var a = 4
}
foo()
console.log(a) // 报错 a is not defined
画出下面代码执行的作用域链
var global
function a(){
var aa = 123
function b(){
var bb = 345
}
b()
}
a()
-
第一步 a 定义
-
第二步 a 执行
-
第三步 b 定义
没有 a 执行就不会有 b 定义,所以 b定义 和 a执行 是一样的
-
第四步 b 执行