在看js权威指南时,感觉上面讲的不太详细,没看懂什么意思,就找了有关的视频,将视频讲解记录下来并加以整理,防止自己遗忘,以下是正文。
在介绍作用域与作用域链之前,先要了解运行(执行)上下文的概念,运行期上下文的定义为:当函数执行时,会创建一个称为执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,它所产生的执行上下文被撤销。
[[scope]]:每个javascript函数都是一个对象,对象中有些属性我们可以访问,有些不可以,这些属性仅供javascript引擎存取,[[scope]]就是其中一个,[[scope]]就是我们所说的作用域,其中存储了运行期上下文的集合,是对象的一个隐式属性,不能使用。
作用域链:[[scope]]中所存储新的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫做作用域链。
查找变量:在哪个函数中查找变量,就在哪个函数生成的作用域链的顶端(第零位)依次向下查找。
举个例子:
function a() {
function b() {
var b = 234;
}
var a = 123;
b();
}
var glob = 100;
a();
// 函数被定义时,其scope中就存了东西,存的Global Object
a定义 a[[scope]]中存0:GO{}(全局对象)
a执行 a[[scope]]中存0:AO{}(活动对象),
1:GO{}
b被创建时,保存了a的劳动成果(换句话说,b是站在a的肩膀上看世界),与a的作用域链完全一样
b在执行时,也要生成自己的执行上下文(AO),置于作用域链顶端
b执行完之后,销毁自己的执行上下文,(与自己的AO断开联系,对比上图红线部分表示已断开)
b执行完后,因为b()是a()的最后一条语句,因此a要销毁自己的执行上下文,b函数也因此被销毁,b函数(已被销毁)与自己的作用域链断开链接(从图中可以看出b函数已经不存在)
当a()被再次执行时,就会生成全新的执行上下文,又产生一次b()的定义,又一个全新的b函数保存了a的劳动成果 ,再次等待执行,执行时又生成一个全新的执行上下文的作用域链。
又一个栗子:
function a() {
function b() {
function c() {
}
c();
}
b();
}
a();
a defined a.[[scope]]-->0:GO;
a doing a.[[scope]]-->0:aAO
1:GO;
a的执行产生b的定义
b defined b.[[scope]]-->0:aAO
1:GO;
b doing b.[[scope]]-->0:bAO
1:aAO
2:GO;
b的执行产生c的定义
c defined c.[[scope]]-->0:bAO
1:aAO
2:GO;
c doing c.[[scope]]-->0:cAO
1:bAO
2:aAO
3:GO;
当c被执行完,就返回到c被定义的状态,如果c在此状态又执行一次,则生成一个新的cAO,与之前的cAO是不同的,但bAO,aAO,GO都是相同的,因为都是基于c的定义。
得出结论:访问函数时,只要访问其作用域链就可以,(只能从里往外看,不能从外往里看),所有的AO和BO都是一样的
注:只有a执行才会导致b被定义