[[scope]]:
每个JavaScript函数都是一个对象,对象中有些属性我们可以访问,有些不可以,这些属性仅供JavaScript引擎存取,[[scope]]就是其中一个。
[[scope]]指我们所说的作用域,其中存储了执行期上下文的集合。
执行期上下文:当函数执行时,会创建一个称为执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,它所产生的执行上下文被销毁。
作用域链:
[[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫做作用域链。
当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执行的代码所在环境的变量对象。
function a() {
function b() {
var bb = 234
}
var aa = 123
b()
}
var glob = 100
a()
对这样一段代码 作用域链的过程如下:




函数b执行完成之后,删除作用域链的第一个AO,回到刚被定义的状态,等待下次执行,下次执行时,重新创建一个新的AO
同理,函数a执行完成之后,也删除其第一个AO,回到刚被定义的状态,此时b函数直接没有了,等到下次a函数执行,重新创建一个新的AO,即又创建了一个新的函数b
函数b被定义的时候,作用域链的第一个AO,就是函数a执行时候作用域链的第一个AO,如下图所示:

也就是 这个过程:


所以,搞清楚作用域链之后我们知道:
内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中的任何变量和函数。这些环境之间的联系是线性,有次序的。每个环境都可以沿着作用域链向上搜索,以查询变量和函数名;但任何环境都不能通过向下搜索作用域链而进入另一个执行环境。搜索过程是从作用域链的顶端开始,逐级的向后回溯,直至找到要找的变量或函数名为止。
实际上闭包的实现是这样的:
可以先看我作用域及作用域链这节

对这段代码,

a执行,然后定义了b,并把b给保存出来
然后a执行结束,把作用域链的第0位删除,但此时a的AO没有被垃圾回收,因为还有b的作用域链引用着它,如下图所示。

所以b被保存到外部之后,还可对a中的AO进行操作,即还可以访问函数a里的变量aaa,所以执行demo后,能打印出aaa,也可对aaa进行操作。

网友评论