摘要:因此我们可以说变量对象包含了活动对象,活动对象就是作用域链上正在被执行和引用的变量对象。
看一下是知乎大神对于 js 执行环境 活动对象 变量对象 作用域链的解释
假设在全局环境下定义了函数pub()和变量pubvar:
var pubvar = 1; function pub () { var pravar = 2; return pubvar + pravar; } alert(pub(2)); //调用pub()函数
当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain),这个作用域链包含了全局环境的变量对象(执行环境中定义的所有变量和函数都保存在这个对象中)并被保存在pub()函数内部的scope属性中。但是,当我们打开浏览器的时候已经存在了一个全局的执行环境,这个全局的执行环境属于浏览器,JS里浏览器被称为window对象,我们把这个环境叫做A环境,只要没有关闭浏览器,A环境会一直存在下面会提到执行环境什么时候会被创建。我们用色块表示执行环境,链条表示作用域链,作用域链上半部分是活动对象区域,下半部分是变量对象区域,如下图:
当我们调用pub()函数的时候,会在全局执行环境A中创建一个执行环境B,没错,执行环境如其名是在运行和执行代码的时候才存在的,所以我们运行浏览器的时候会创建全局的执行环境。这个时候根据pub()函数scope属性中的作用域链把pub()函数内的变量对象放入新的B环境中,作用域链也得到更新,如下图:
上图的虚线表示正在执行,全局变量对象此时处于作用域链的第二位所以标号变成了1。你可能也注意到那个arguments对象,它是在函数被创建的时候就一直存在的,无需用户创建。arguments对象保存的是函数圆括号内定义的参数,准确来说保存的是参数的值,因这里我们没有设置参数,所以显示未定义。此时我们把属于B环境的变量对象(也就是pub()函数中的所有函数和变量)叫做活动对象。因此我们可以说变量对象包含了活动对象,活动对象就是作用域链上正在被执行和引用的变量对象。我们从活动对象的名称中也能看出 “执行、运行、激活” 等意味。你可以这样理解,整个代码的运行总有一个起始的对象吧,不管这个起始是变量还是函数,总要有一个称呼,虽然我们把执行环境中的变量和函数的总称叫做变量对象,但这不能反映代码的动态性,为了区别于普通的变量对象,我们创造了活动对象的概念。
我们把上面的代码变成如下:
var pubvar = 1; function pub () { var pravar = 2; return pubvar + pravar; } var pubvar2 = 3; function pub2 () { var pravar = 2; return pubvar2 + pravar; } alert(pub(2)); //调用pub()函数
这个时候全局的作用于链和执行环境如下
接着我们调用pub()函数,执行环境和作用域链如下:
你看没有被调用的pub2()函数仍然只是闲着,甚至没有被pub()函数在内部引用。由于pub2()没有参与整个pub()函数的调用过程,所以pub2()中不存在活动对象,只有“处于静止状态”的变量对象,当然也没有创建执行环境(因为它根本没执行嘛)。
到这里就完了?也没有,我们刚才也只是讨论了两个平行且毫不关联的函数其中一个被调用的状况,言下之意就是也存在函数相互影响的例子,最典型的就是闭包,闭包是一种函数嵌套的情况。定义如下代码:
function returnfunc (propertyName) { return function (obj) { //-----这行定义并返回了一个闭包,也被称之为一个匿名函数 return obj[propertyName]; //这里用方括号法访问属性,因为属性是变量(returnfunc()函数的参数) }; } var savefunc = returnfunc("name"); //调用returnfunc() var result = savefunc({name:"Picasso"});//调用savefunc() alert(result); //返回字符串“Picasso”
最开始的执行环境和作用域链
我们先开始调用returnfunc()函数,马上会创建一个包含returnfunc()变量对象的行环境,作用域链开始变化,如下图:
图的白色虚线表示执行程序产生的效果,它可能表示的是返回一个结果、复制某种值、产生一个新物体、建立某种联系等。
题外话:你会发现上图的arguments参数的值和propertyName的值是一样的,这是因为arguments保存的就是参数,采用实时映射的方式与参数建立联系,如果你在returnfunc()函数内再加一个值为{name:"picasso"},名为obj的参数,那么arguments的值变成[{name:"nicholas"},{name:picasso}],是的,你没看错,arguments是一个数组!!!
随后returnfunc()函数会返回它内部的匿名函数,当匿名函数被返回后,整个作用域链和执行环境又发生了变化:
我们看到匿名函数(闭包)被添加到了最作用域链的最前端,returnfunc()的执行环境被销毁,但我们注意到returnfunc()函数的活动对象仍然在被引用(匿名函数仍在访问propertyName参数),因此returnfunc()函数的变量对象仍然在内存中,成为活动对象。这就是为什么匿名函数就能访问returnfunc()函数定义的所有变量和全局环境定义的变量,毕竟returnfunc()的活动对象仍然保持“激活”状态。
根据上面所述,随着代码一行一行的被执行、执行环境不断被创建和销毁、变量对象间的各种关系被建立,这些背后的逻辑导致活动对象也在不断变化,这足以证明活动对象只是正在被执行和引用的变量对象。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/92808.html
摘要:至此作用域链创建完毕。好了,通过深入理解作用域链,我们能跟好的理解的运行机制和闭包的原理。 前言 理解javascript中的作用域和作用域链对我们理解js这们语言。这次想深入的聊下关于js执行的内部机制,主要讨论下,作用域,作用域链,闭包的概念。为了更好的理解这些东西,我模拟了当一个函数执行时,js引擎做了哪些事情--那些我们看不见的动作。 关键词: 执行环境 作用域 作用域链 变...
摘要:全局执行环境的变量对象始终是作用域链中的最后一个变量对象。综上,每个函数对应一个执行环境,每个执行环境对应一个变量对象,而多个变量对象构成了作用域链,如果当前执行环境是函数,那么其活动对象在作用域链的前端。 1.几个概念 先说几个概念:函数、执行环境、变量对象、作用域链、活动对象。这几个东东之间有什么关系呢,往下看~ 函数 函数大家都知道,我想说的是,js中,在函数内部有两个特殊...
摘要:下面我们就罗列闭包的几个常见问题,从回答问题的角度来理解和定义你们心中的闭包。函数可以通过作用域链相互关联起来,函数内部的变量可以保存在其他函数作用域内,这种特性在计算机科学文献中称为闭包。 写这篇文章之前,我对闭包的概念及原理模糊不清,一直以来都是以通俗的外层函数包裹内层....来欺骗自己。并没有说这种说法的对与错,我只是不想拥有从众心理或者也可以说如果我们说出更好更低层的东西,逼格...
摘要:所以,全局执行环境的变量对象始终都是作用域链中的最后一个对象。讲到这里,可能你已经对执行环境执行环境对象变量对象作用域作用域链的理解已经他们之间的关系有了一个较清晰的认识。 JavaScript中的执行环境、作用域、作用域链、闭包一直是一个非常有意思的话题,很多博主和大神都分享过相关的文章。这些知识点不仅比较抽象,不易理解,更重要的是与这些知识点相关的问题在面试中高频出现。之前我也看过...
阅读 1020·2021-11-15 18:11
阅读 3132·2021-09-22 15:33
阅读 3444·2021-09-01 11:42
阅读 2610·2021-08-24 10:03
阅读 3594·2021-07-29 13:50
阅读 2908·2019-08-30 14:08
阅读 1233·2019-08-28 17:56
阅读 2242·2019-08-26 13:57