为啥 arguments.callee 会损害性能?

Posted

技术标签:

【中文标题】为啥 arguments.callee 会损害性能?【英文标题】:Why does arguments.callee hurt performance?为什么 arguments.callee 会损害性能? 【发布时间】:2014-06-17 15:44:51 【问题描述】:

使用arguments.callee 的替代方法是简单地命名函数,如下所示:

// Snippet 1, using arguments.callee:
(function()
    document.body.innerhtml += 'qwe';
    setTimeout(arguments.callee, 1);
)()

// Snippet 2, using naming:
(function f()
    document.body.innerHTML += 'qwe';
    setTimeout(f, 1);
)()

是什么阻止了 javascript 引擎/编译器自动将 Snippet 1 优化为上面的 Snippet 2?是否存在一些固有的限制?

MDN's argument 基本上可以归结为:

..arguments.callee 严重阻碍了内联等优化 功能,因为它必须能够提供参考 如果访问了arguments.callee,则为未内联函数。

但是,如果我们手动命名函数并通过它的名称调用它,我们已经提供了对该函数的引用,因此“阻碍了像内联函数这样的优化”。

Olliej's argument 基本上是“内联和尾递归 [变得] 在一般情况下是不可能的 [而如果使用命名则可能]”。然而,没有提供任何证据,这似乎是一种挥手(另见他帖子下方的 cmets)。

为什么函数命名比使用arguments.callee 更高效?

【问题讨论】:

我认为 MDN 指的是命名函数表达式,而不是分配给变量的匿名函数表达式(即(function f()))。 "Why was arguments.callee removed from ES5 strict mode?" section of the MDN article 的第一行写着“(改编自a Stack Overflow answer by olliej) 【参考方案1】:

根据我的阅读,MDN 并不是说​​“很难提供对非内联函数的引用”;相反,它是在说“很难确保当您访问 arguments.callee 时,您会获得对未内联函数的引用”。

(这只是您问题的一半答案,因为我仍然不清楚为什么arguments.calleearguments 的其余部分或this 更难保持最新状态. 所以这个论点,就目前而言,显然并不令人信服。但我认为 MDN 就是这么说的。)

【讨论】:

但是编译器不能确保访问arguments.callee 会返回对该函数的引用,因为它可以(以及其他替代方法)观察到arguments 在调用@ 之前没有更改987654327@? 无论如何不要粗鲁,但我认为这篇文章更多的是评论...... @Pacerier:我想,是的,智能编译器可以做到这一点,但它过于复杂(因此没有完成)。 olliej 柱子上的 cmets 朝同一个方向领先。 @Bergi,嗯,我不认为是这种情况(因为他们经常做更复杂的事情)......为此,设置一个指示 @987654328 的标志不简单吗如果函数体对其进行了赋值,@ 是否会被修改?在strict 中弃用它的决定似乎表明存在一些硬性限制,未来的编译器无法克服。 @Pacerier:鉴于arguments 对象可以保存在变量中,传递给其他函数等等,我认为解释器静态确定是否arguments.callee 已修改。 @Pacerier:另外——我考虑将其发布为评论而不是答案。我决定将其发布为答案,因为它的重点是您的问题的前提是错误的。如果这不是答案,则没有没有答案,应该关闭/删除问题;但我不希望这个问题被关闭/删除,因为它很聪明而且很有价值,只是建立在一个小错误之上。

以上是关于为啥 arguments.callee 会损害性能?的主要内容,如果未能解决你的问题,请参考以下文章

arguments.callee用法

arguments.callee的用法

arguments.callee 调用函数自身用法

我对arguments.callee的理解

在严格模式下复制 arguments.callee

arguments.callee Function.callee arguments.caller总结