JS完美收官之——作用域

法医

       每一个对象都有属性和方法,属性和方法是对象的两个基本特性,都是为了存值的。对象可以有属性,一切为对象的东西都可以有属性,那么这个东西是对象的话一定有属性,三段论对吧!古希腊哲学。

function函数也是特殊对象,它身上也有属性,比如说:

function text(){
}

函数text身上有   text.name 和text.prototype 等属性, 它是一种特殊对象——函数类对象,这些是我们可以访问的属性,但还有一种属性是我们访问不了的,比如说:[[scope]],计算机术语叫域的意思,text.[[scope]]这里面存的就是由这个函数产生的作用域,这个属性是隐式的,我们是没有办法拿出来使用的。那么这个属性是给谁用的呢?其实是这样的:系统会通过内部的一些原理定期地调用[[scope]],但是它不会让开发者使用的,只能系统内部使用。

作用域解释:

[[scope]]:每个javascript函数都是一个对象,对象中有些属性我们可以访问,但有些不可以,这些属性仅供javascript引擎存取,[[scope]]就是其中一个。[[scope]]指的就是我们所说的作用域,其中存储了运行期上下文的集合。

这里提到一个运行期上下文的概念:什么是运行期上下文?当在函数执行的前一刻,会创建一个称为执行期上下文的内部对象(activation object)。一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行期上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行上下文,,当函数执行完毕后,它所产生的执行期上下文会被销毁,属于渣男类型的,用完就丢掉

一个函数在执行的时候产生唯一一个AO(activation object),那里面为什么放的是一个集合啊?

作用域链(scope chain):[[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫作用域链。

接下来我们看一个例子:

function a(){

}
var glob = 100;
a();

01 a函数被定义的时候,它就有自己的属性和方法了,比如说a.name,那么同时肯定有一个a.[[scope]]来存它的作用域,a.[[scope]]里面存的是啥呢?请看下面图解:

如图此时[[scope]]里面存了一个作用域链(scope chain),作用域链里面装了一个执行期上下文的集合,但是此时还没有达到一个一个集合,作用域链里面就一个人——第0位的Global Object(全局的执行期上下文)。

02  a函数执,当a函数被执行的时候,它会产生一个局部的执行期上下文AO(activation object),然后AO会被放到作用域链的最顶端,看图:

当我们在一个函数中访问变量的时候,都是先从自己身上找,自己身上没有了就去父级上找,父级再没有了就去全局变量中找。在这个查找的过程中冥冥之中好像有线牵引着一样,一级一级往下找,这种牵引的线就是作用域链。

03  我们先接着上一段代码写,给a函数里面加了个b函数

function a(){
    function b(){
        var b = 234;
    }
    var a = 123;
    b();
}
var glob = 100;
a();

有了第一步和第二步的过程思路之后,我们再来看看以上代码的执行过程,当a函数被定义的时候产生了GO(global object),随后,a函数执行的时候生成AO(activation object),同时,当a函数执行的时候产生了b函数的定义,a函数被定义的时候是在全局的环境中出生的,而b函数定义则是站在a函数的的肩膀上出生的,a函数里面能看到的东西,b函数都能看到,所以说b函数拿到的是a函数的劳动成果吧,如图:

b函数创建完成后,接着就是b执行,b函数执行产生一个新的AO并且放到作用域链的最顶端,然后在b里面访问变量的顺序是自高而下从0依次到2访问,如图

当b函数执行完毕之后,执行期上下文会销毁,其实销毁是把它自己的作用域链那条线给剪断了,b函数销毁之后,接着a函数也执行完了,a函数上下文随之也会销毁,但是要看清楚,a函数里面有个b函数,a函数销毁后从此b函数就没了,永远都没了。然后a函数又回归被定义的状态,等待下一次被执行,当a函数再次被执行的时候,产生独一无二的执行期上下文放在作用域的最顶端,接着a函数的执行又产生b函数的定义,b函数又站在在a函数的肩膀上看世界,在a函数生成的执行期上下文的环境下,生成自己的AO,然后b函数执行完又销毁,完了a函数再销毁,周而复始的执行  a被定义——>a被执行过程 &&b被定义——>b被执行——>b被销毁——>a被销毁  这一过程。

接下来我们看一个小例子,加深一下作用域执行过程:

function a(){
function b(){
    function c(){            
    }
    c();
}
b();
}
a();

2.png

从上面的执行过程中我们可以知道,在任何一个函数里面我们要访问一个变量就去找函数执行产生的作用链里面找就行了。

我们还可以明白一点:在外面的函数为什么没办法往函数里面去访问,我们站在b的AO里面根本看不到c的AO里面的东西。

我们还要明白一点,以上所有的aAO、bAO、GO都是同一个人,只是它们互相借用了下而已。

阅读 581
17 声望
3 粉丝
0 条评论
你知道吗?

17 声望
3 粉丝
文章目录
宣传栏