目前市面上不少文章一大抄,在现在 ES202+ 的年代,还在摘抄着 ES3 的原文。html
Every execution context has associated with it a variable object. Variables and functions declared in the source text are added as properties of the variable object. For function code, parameters are added as properties of the variable object.
而后将其与“面试官”绑在一块儿。其实在书面理解上沿用活跃对象的概念没什么问题,可是照抄原文又不指明出处,就会让人误觉得现在的规范中也还定义了活跃对象这一律念。其实上引文中包含了活跃对象(Activation Object, AO,有时也称活动对象、激活对象)与可变对象(Variable Object, VO,有时也称变量对象)的内容,摘抄自 ECMAScript 3 Spec 的两处并组装起来。面试
今天,这里与你们一块儿浅尝一下 JavaScript 中的活跃对象。网络
在 ECMAScript 1 和 ECMAScript 3 中,的确是有着关于活跃对象的定义。数据结构
当控制进入函数代码的执行上下文时,建立一个活动对象并将它与该执行上下文相关联, 并使用一个名为
arguments
、特征为{ DontDelete }
的属性初始化该对象。该属性的初始值是稍后将要描述的一个参数对象。 闭包接下来,这个活动对象将被用做变量初始化的可变对象。 ecmascript
活动对象纯粹是一种规范性机制,在 ECMAScript 访问它是不可能的。只能访问其成员而非该活动对象自己。对一个基对象为活动对象的引用值应用调用运算符时,此次调用的
this
值 为null
。函数——ECMAScript Language Specification 262 Edition 3 Final, 10.1.6 活跃对象this
但也仅限于 ECMAScript 1 和 3 了。咱们如今在网上(尤为是中文搜索环境中)获取到的关于活跃对象和可变对象(Variable Object)的文章,大多都是为咱们描述的 ECMAScript 1 和 3,早已过期。es5
若是你们对这块内容仍然感兴趣(实际上我也建议你们感兴趣),能够参阅:spa
在 ES5 及以后的 ES 版本,已经不存在活跃对象(AO)及一系列周边内容的概念了。取而代之,是一个叫词法环境(Lexical Environments)的定义。
也就是说,严谨来说,现代的 ECMAScript 早已没有了活跃对象这一律念,因此当网络上文章中“面试官跟你聊起 AO”这些内容出现的时候,其实就是“市面文章一大抄”的体现。他们还会有理有据地把 ECMAScript Spec 原文给你列出来(参照文首的摘抄)。
关于词法环境,你们能够参阅:
这里就不赘述了。
通过上面两节内容,咱们能够知道,活跃对象是 ECMAScript 1 / 3 中的内容。后续的版本中,其就不复存在了。可是活跃对象这个概念就不能再被提起了吗?
其实也不是,它对应的概念仍是能够延续下来的。只不过不能让人误觉得现代 ECMAScript 中还有其定义,咱们如今再聊起活跃对象时,应该知道它只是广义的抽象,而再也不是狭义的定义了。广义的活跃对象在不一样的场景下也能够有不一样的名字,如活跃记录(Activation Record)、栈帧(Stack Frame)等。
每当函数被调用的时候,其都会建立一个活跃对象。该对象对开发者不可见,是一个隐藏的数据结构,其中包含了一些函数在执行时必要的信息和绑定,以及返回值的地址等等。
在 C 语言中,这个对象会在一个栈中被分配生成。当函数返回的时候,该对象会被销毁(或者出栈)。
你看,此处“活跃对象”被引伸到 C 语言了。它指的是一个抽象的存在,意为栈帧(Stack Frame)。
JavaScript 与 C 语言不一样,它是从堆中分配该对象。且这个活跃对象并不会在函数返回时被自动销毁,它的生命周期与普通对象的垃圾回收机制相似,是根据引用数量决定的。
一个活跃对象包含:
return
以后的控制权转移;undefined
进行初始化;this
,若是函数做为一个方法被调用,那么 this
一般就是它的宿主对象。其实 ES5+ 以后的广义“活跃对象”就是对于 ES 1 / 3 定义的活跃对象的一个扩展,并将其应用到了词法环境中。
至此为止,关于“活跃对象”的浅析就足矣。当下环境中,咱们不是不能再谈论“活跃对象”,而是不能乱谈,还谈得有鼻子有眼的。现现在的“活跃对象”是一个相似于活跃记录和栈帧的广义抽象概念。
否则,仍旧用老旧的文章去回答所谓“面试官”的问题,颇有可能被刷掉哦。
闭包也是老生常谈的一个概念。为何在这篇文章中要提起这么个看起来八竿子打不着的概念呢?
闭包一直没有一个很是严谨的定义。如:
闭包就是可以读取其余函数内部变量的函数。
闭包就是可以读取外层函数变量的函数。
等等等等。
再例如:
「函数」和「函数内部能访问到的变量」(也叫环境)的总和,就是一个闭包。
上述的解释也都是我从网上的各文章中摘抄出来的。其实理解起来很容易,可是语言描述出来并不那么严谨。你们知道那么回事就行了。
不过,在咱们有了广义活跃对象以后,咱们能够从另外一个角度来定义闭包了。怎么说呢?函数是可嵌套的。当一个嵌套的函数对象被建立时,它会包含一个外层函数对象所对应的活跃对象引用
有了这层关系,闭包就好定义了:
一个拥有外层函数对象所对应的活跃对象引用的函数对象就被称为闭包。
言简意赅。虽然不至于像“能读取外层函数中的变量”那样亲民朴实,但也很是言简了。同时,有了“活跃对象”做为大前提,已经帮忙作了不少前提条件定义,因此这个定义也能达到意赅的效果。
之后再面试起什么是闭包,你们能够尝试从这个角度解释哦。前提是你真的懂了,不要到时候又被面试官给绕进去了。