更改对象的[[Prototype]]后,JavaScript环境最终会恢复吗?

时间:2018-02-14 20:05:53

标签: javascript performance prototype v8 javascript-engine

所以,我读过MDN disclaimers and warnings,我读过great answer on the subject,但我仍然想知道。这个问题实际上来自我给另一个问题的回答here

假设我决定做肮脏的行为。我会为我的余生而后悔的事情。有些东西会永远羞辱我,羞辱我的姓氏。一个有目的,蓄意的结局 -

好吧,够了。无论如何,这是:

let proto = Object.getPrototypeOf(Function.prototype);

Object.setPrototypeOf(Function.prototype, {
  iBetterHaveAGoodReasonForDoingThis : "Bacon!"
});

//just to prove it actually worked
let f = (function(){});
console.log(f.iBetterHaveAGoodReasonForDoingThis);

// Quick, hide the evidence!!
Object.setPrototypeOf(Function.prototype, proto);

基本上,我在那里做的是改变Function.prototype的原型,这个对象几乎影响你可以编写的每一段JavaScript代码。然后我把它改回来了。

我想说明原型链中的一个重大变化会影响很多代码并导致很多优化工作耗尽。我不希望改变它会修复任何东西(如果有的话,我希望它会使性能更糟糕)。我很想知道它是否会,但如果确实如此,那不是我的意图。

我只是想知道,在这样的改变之后,JavaScript环境是否会开始恢复并再次开始优化?或者它会永远放弃并以去优化模式运行所有东西?是否存在因此而永远无法实现的优化?我能相信,经过一段时间的恢复后,它会恢复到常规状态吗?

对于上下文,我说的是像最新版本的V8这样的引擎,而不是像Internet Explorers这样的东西使用的原始垃圾。我理解不同系统的答案可能有所不同,但我希望它们之间有一些共性。

1 个答案:

答案 0 :(得分:8)

V8开发者在这里。这个问题没有一个简单的答案。

大多数优化将“回归”(当然,代价是花费额外的CPU时间)。例如,必须抛弃的优化代码最终会被重新编译。

某些优化将永久保持禁用状态。例如,V8会在(并且只要)知道原型链未被破坏时跳过某些检查。如果它看到一个应用程序修改原型链,那么从那时起就可以安全地使用它。

为了使事情变得更加复杂,细节会随着时间而变化。 (这就是为什么在这里列出更具体的情况没有多大意义,抱歉。)

背景:

JavaScript中有许多地方,代码可能做某件事,JavaScript引擎必须检查,但大多数代码都没有这样做。 (例如,继承数组原型中缺少的元素:['a', ,'c'][1]几乎总是返回undefined除了,如果有人Array.prototype[1] = 'b'Object.prototype[1] = 'b' 。)因此,当为函数生成优化代码时,引擎必须在两个选项之间做出决定:

(A)总是检查有问题的东西(在示例中:遍历数组的原型链并检查每个原型以查看它是否在该索引处有一个元素)。假设执行此代码需要2个时间单位。

(B)乐观地假设数组原型没有元素,并跳过检查(在示例中:甚至不查看原型,只返回undefined)。假设这会将执行时间缩短到1个单位(两倍的速度,是的!)。但是,为了正确起见,引擎现在必须密切关注所有阵列的原型链,如果任何元素出现在任何地方,必须找到并扔掉所有基于此假设的代码,代价为1000时间单位。

考虑到这种权衡,发动机首先遵循快速但风险较高的策略(B)是有道理的,但是当它甚至只失败一次时,它会切换到更安全的策略(A),以避免必须再次支付1000次单位罚款的风险。

你可以争论“即使只是一次”是最佳门槛,还是一个网站在放弃(B)之前是否应该获得2,3或更多的免费通行证,但这并不会改变基本的权衡。