【问题标题】:Why does Javascript engine need to create an Activation Object each time a function is called?为什么Javascript引擎每次调用函数都需要创建一个Activation Object?
【发布时间】:2012-10-30 12:41:06
【问题描述】:

总结作用域链的概念:

加载网页后,Javascript 会定位函数定义并为每个定义创建一个所谓的变量对象。 每个 VO 必须引用每个局部变量(或全局),因此从第一个祖先的函数开始,直到全局上下文。 每个函数的作用域链都存储在名为:Scope 的函数属性中。

此外,当调用函数时,会创建一个新对象:激活对象

这是什么? :

它就像一个变量对象(实际上它是一个VO),负责引用所有函数内部的变量对象,包括“参数”对象和形参。

当然,函数祖先的变量对象+函数的激活对象组成的链中的每一个首先将至少所有变量映射到undefined。然后,只要执行进行,它就会通过更新其值(对应于引用的变量)来进化。

但是,我注意到激活对象与变量对象不同,仅仅是因为它包含 Arguments 对象,并且这一事实将阻止它在函数被调用之前被创建。

所以,我想知道为什么构建 Javascript 引擎的人没有在函数的定义步骤分配每个激活对象。因此,当调用函数时,无需创建自己的特定激活对象,因为它已经存在。引擎会在函数执行结束时清除相应的参数对象,以便下次调用该对象时不会产生副作用。

它会提高性能吗?实际上,在每次调用时重新创建一个完整的激活对象可能会消耗......或者这个提议有问题吗?

【问题讨论】:

  • 我相信从 ECMAScript 5 开始没有“激活对象”。它现在被称为“可变环境”。另外,this excellent article by Angus Croll 可能有助于澄清一些事情。
  • 在像 C 这样的旧语言中,“激活记录”是在堆栈上分配的——换句话说,它是“堆栈帧”。在 JavaScript 中,当函数通过实例化一个函数并返回它(或将其绑定到某个全局对象)来公开一个闭包时,激活记录可以在函数调用结束后“存活”。

标签: javascript function scope


【解决方案1】:

激活对象表示函数调用的上下文。每个调用都必须有自己的对象。它们是允许关闭等的原因。

可以将其视为类似于为调用 C 或 C++ 函数而分配的堆栈帧。

edit — 这是一个示例函数:

function makeCounter( count ) {
  return function() {
    return count++;
  };
}

现在,我可以用它来做一个计数器功能:

var counter1 = makeCounter(1);
alert(counter1()); // alerts "1"
alert(counter1()); // alerts "2"

如果我再做一个呢?

var counter100 = makeCounter(100);
alert(counter100()); // alerts "100"

如果对makeCounter() 的两个调用共享一个arguments 实例,那么当我随后调用“counter1()”时会发生什么?

【讨论】:

  • 是的,但这与我写的并不矛盾。我想知道为什么这些激活对象中的每一个都不是仅在函数定义步骤中创建的。
  • @Mik378 因为该对象代表函数的每个不同的调用。每个调用必须有自己的arguments实例等。
  • 这就是我所说的:)“引擎只会清除相应的参数对象”。例如 test(color) 函数在调用执行时创建了自己的激活对象。我的问题是:为什么不在函数定义步骤创建它并在每次调用同一个函数时刷新它(清除类似数组的参数对象),而不是每次都重建所有局部变量映射。因为无论如何,内部局部变量被分配给 undefined 直到执行进行并更新它们。
  • arguments 对象表示参数,它们是调用上下文的一部分。如果函数调用返回一个函数,而该函数又引用了原始函数中的参数怎么办?如果参数实例后来被清除,那么闭包就会被破坏。
  • @Mik378 查看答案的编辑。请注意,由于arguments 的工作方式很奇怪,伪数组的元素实际上是参数的别名。
【解决方案2】:

每个函数不能有一个激活对象,在调用之间重复使用,因为在任何给定时间可能有多个函数调用在进行中。一个明显的例子是递归。

也许你可以为每个函数分配 1 个 AO,所以至少 first 调用可以使用它,但我想这种机制只会使充其量只是名义上的性能提升(同时也牺牲了内存)的概念。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-28
    • 2018-12-19
    • 1970-01-01
    • 2020-05-10
    • 2016-04-08
    相关资源
    最近更新 更多