写点什么

JS 完美收官之——作用域

用户头像
法医
关注
发布于: 3 小时前
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();
复制代码


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



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


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



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


我们先接着上一段代码写,给 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();
复制代码



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


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


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

发布于: 3 小时前阅读数: 3
用户头像

法医

关注

公众号@前端猎手 2020.07.17 加入

我是法医,一只治疗系前端码猿🐒,与代码对话,倾听它们心底的呼声,期待着大家的点赞👍与关注➕。 [微信:wKavin]

评论

发布
暂无评论
JS完美收官之——作用域