作用域、作用域链精解
作用域精解
// 函数是一种特殊的对象,函数也有属性
// test.name 特殊类对象 函数对象
function test() {
}
[[scope]]:
-
每个javascript函数都是一个对象,对象中有些属性我们可以访问,但有些不可以,这些属性仅供javascript引擎存取,[[scope]]就是其中一个。
-
[scope]]指的就是我们所说的作用域,其中存储了运行期上下文的集合。
// [[scope]] 由这个函数产生而产生的作用域 这是一个隐式的属性 // 系统会通过它内部的一些原理去定期的调用这个[[scope]] 但不会让你用
作用域链:
[[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫做作用域链。
function a() { // a刚刚出生的时候 它的scope里面就已经存东西了 存的是GO(准确的说 a存的东西是它所在环境的那个执行上下文 又因为这个a是全局的 所以存的是GO)
function b() {
var bb = 234;
}
var aa = 123;
b();
}
var glob = 100;
a();
// a函数被定义: a.[[scope]] -- > 0 : GO {} 第0位装的是GO
// a被定义完之后需要执行 看下图理解
// a函数被执行: a.[[scope]] -- > 0 : AO {} 执行第0位装的是新建的AO,第1位装的是GO
// 因为b在a里面 所以a执行了b才能被定义 b直接拿a的劳动成果 有点像继承
// b函数出生的时候就是在a中 也就是看到的就是a的环境
// b.[[scope]] -- > 0 : AO {} 定义时第0位是新建的AO,第1位装的是GO
// b函数在执行时生成自己的AO
// b.[[scope]] -- > 0 : AO {} 执行时第0位指向自己新建的AO,第1位指向a的AO,第2位指向GO
a函数被创建时,发生如下过程:第0位指向GO

a函数被执行时,发生如下过程:执行第0位指向新建的AO,第1位指向GO,函数执行之前产生AO,执行之后销毁,a会销毁自己产生的那个AO,销毁方式就是把线剪断,回到被定义的状态,等待下次执行,又会建立一个新的AO。注意这里剪断了会把b函数的定义也销毁,下一次a函数执行时又会产生一个全新的b函数的定义,b函数又可以拿a的劳动成果,然后创建自己的AO。

b函数被创建时,发生如下过程:b函数出生的时候就是在a中 也就是看到的就是a的环境,第0位指向AO,第1位指向GO

b函数被执行时,发生如下过程:执行时第0位指向自己新建的AO,第1位指向a的AO,第2位指向GO, 函数执行之前产生AO,执行之后销毁,b会销毁自己产生的那个AO,销毁方式就是把线剪断,回到被定义的状态,等待下次执行,又会建立一个新的AO。

运行期上下文:
当函数执行时(执行前一刻),会创建一个称为执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时的环境(变量提升函数提升啥的),函数每次执行时对应的执行上下文都是独一无二的(每次都会产生一个新的AO),所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,它所产生的执行上下文被销毁。函数执行之前产生AO,执行之后销毁
查找变量:
从作用域链的顶端依次向下查找。(在哪个函数查找变量,就在哪个函数的顶端依次向下查找)
看上图理解,从作用链的顶端找到底端。(也就是从AO先找,再找GO)
练习
function a() {
function b() {
function c() {
}
c();
}
b();
}
a();
// 1. a函数定义时 第0位指向GO
// 2. a函数执行时 第0位指向新建的AO 第1位指向GO
// 3. b函数定义时 第0位指向a的AO 第1位指向GO
// 4. b函数执行时 第0位指向新建的AO 第1位指向a的AO 第2位指向GO
// 5. c函数定义时 第0位指向b的AO 第1位指向a的AO 第2位指向GO
// 6. c函数执行时 第0位指向新建的AO 第1位指向b的AO 第2位指向a的AO 第3位指向GO