在javascript中,访问“window.Math”比访问没有“window”的“Math”对象慢还是快?

在javascript中,访问“window.Math”比访问没有“window”的“Math”对象慢还是快?,javascript,performance,window,global-variables,global,Javascript,Performance,Window,Global Variables,Global,我有点好奇,在javascript中引用“全局”名称空间时,最佳实践是什么,它仅仅是指向窗口对象的快捷方式,或是相反版本,具体取决于您如何看待它 我想知道: var answer = Math.floor(value); 好于或坏于: var answer = window.Math.floor(value); 在性能、资源使用或兼容性方面是更好还是更差,哪怕只是一点点 一个有稍微高一点的成本吗?像一个额外的指针之类的东西 编辑注:在大多数情况下,我的可读性高于性能,但在这种情况下,我忽略了

我有点好奇,在javascript中引用“全局”名称空间时,最佳实践是什么,它仅仅是指向窗口对象的快捷方式,或是相反版本,具体取决于您如何看待它

我想知道:

var answer = Math.floor(value);
好于或坏于:

var answer = window.Math.floor(value);
在性能、资源使用或兼容性方面是更好还是更差,哪怕只是一点点

一个有稍微高一点的成本吗?像一个额外的指针之类的东西


编辑注:在大多数情况下,我的可读性高于性能,但在这种情况下,我忽略了可读性的差异,只关注性能。

JS性能因浏览器而异


我的建议是:对其进行基准测试。把它放在一个for循环中,让它运行几百万次,然后计时。。。。看看你得到了什么。一定要分享你的结果

首先,不要因为性能原因而比较这些东西。显然,Math.round比window.Math.round更容易在眼睛上显示,而且使用其中一种方法不会显著提高性能。因此,不要为了性能的微小提高而混淆代码

然而,如果你只是好奇哪一个更快。。。我不确定全局范围是如何在引擎盖下查找的,但我猜访问窗口与访问Math窗口是一样的,Math生活在同一个级别上,如window.window.window.Math.round working所示。因此,访问window.Math会更慢

此外,通过查找变量的方式,您将看到通过执行var round=Math.round提高性能;调用round1.23,因为所有名称首先在当前本地范围中查找,然后在当前范围上查找,依此类推,一直到全局范围。每个作用域级别都会增加非常小的开销

但同样,不要做这些优化,除非你确信它们会产生明显的变化。可读、可理解的代码对于it在现在和将来的工作方式都很重要

以下是使用Firebug的完整评测:

<!DOCTYPE html>
<html>
    <head>
        <title>Benchmark scope lookup</title>
    </head>
    <body>
        <script>
        function bench_window_Math_round() {
            for (var i = 0; i < 100000; i++) {
                window.Math.round(1.23);
            }
        }

        function bench_Math_round() {
            for (var i = 0; i < 100000; i++) {
                Math.round(1.23);
            }
        }

        function bench_round() {
            for (var i = 0, round = Math.round; i < 100000; i++) {
                round(1.23);
            }
        }

        console.log('Profiling will begin in 3 seconds...');
        setTimeout(function () {
            console.profile();
            for (var i = 0; i < 10; i++) {
                bench_window_Math_round();
                bench_Math_round();
                bench_round();
            }
            console.profileEnd();
        }, 3000);
        </script>
    </body>
</html>
正如你们所看到的,窗户。数学是一个非常糟糕的主意。我猜访问全局窗口对象会增加额外的开销。但是,从全局范围访问Math对象与仅通过引用Math.round函数访问局部变量之间的区别并不是很大。。。请记住,这是100000次呼叫,差异仅为3.6ms。即使有一百万个电话,你也只能看到36毫秒的差异

使用上述分析代码需要考虑的事项:

这些函数实际上是从另一个作用域中查找的,这增加了几乎不可察觉的开销。不过,我尝试将这些函数导入到匿名函数中。 实际的Math.round函数会增加开销,我估计100000次调用中会增加6毫秒。 如果在局部/函数范围内调用Math.round,解释器必须首先检查局部变量,然后在全局/窗口空间中检查。所以在局部范围内,我猜window.Math.round会稍微快一点。这不是程序集,或者C或C++,所以我不会担心哪一个更快,因为性能原因,但是如果出于好奇,确定,基准。p> 正如您所说,Math.floor可能只是window.Math-As-window的快捷方式,在大多数Javascript实现(如V8)中,它是一个Javascript全局对象

Spidermonkey和V8将针对常见用途进行大量优化,因此不应担心

为了可读性,我倾向于使用Math.floor,速度上的差异将是如此微不足道,根本不值得担心。如果您正在进行100000层的测试,那么可能是时候将该逻辑从客户机中切换出来了

您可能想了解一下v8源代码,这里有一些有趣的评论,关于去掉int.Parse one等函数的纳秒数


如果您想知道流程是如何工作的,这可能是一个有趣的问题

范围链是在计算标识符时搜索的对象列表,代码无法访问这些对象,只能访问其属性标识符

首先,在全局代码中,范围链被创建并初始化为只包含全局对象

链中的后续对象是在函数执行上下文中输入时创建的,通过with语句和catch子句创建的,这两个语句还将对象引入链中

例如:

// global code
var var1 = 1, var2 = 2;
(function () { // one
  var var3 = 3;
  (function () { // two
    var var4 = 4;

    with ({var5: 5}) { // three
      alert(var1);
    }
  })();
})();
在上面的代码中,作用域链将包含不同级别的不同对象,例如,在with语句中的最低级别,如果使用var1或var2变量,则作用域链将包含4个需要检查以获取该标识符的对象:with语句引入的对象,这两个函数,最后是全局对象

你 还需要知道窗口只是全局对象中存在的一个属性,它指向全局对象本身。窗口由浏览器引入,在其他环境中通常不可用


总之,当你使用window时,因为它只是一个标识符,不是一个保留字或类似的东西,它需要通过所有的解析过程才能得到全局对象window。数学需要一个由点完成的附加步骤。属性访问器。

就我所理解的JavaScript逻辑而言,您所指的所有内容都是在全局变量范围内搜索的。在浏览器实现中,窗口对象是全局对象。因此,当您请求window.Math时,实际上必须取消引用window的含义,然后获取其属性并在那里找到Math。如果你只是简单地问数学,首先要找的是全局对象

所以,是的-调用Math.something将比window.Math.something更快


D.Crockeford在他的演讲中谈到了这一点,据我回忆,它出现在视频的第三部分。

为什么这很重要?你想解决的问题是什么?嗯,我正在优化性能,所以我有点好奇哪一个更快。如果我做数千次计算,每个循环少一次指针解引用,可能会对我有所帮助。这不是一个真正的问题吗?这是一个好问题。window.Math.round仍然需要查找一个本地窗口变量。+1为我使用var round=Math.round提供了一些有效性。干得好,你在基准测试方面做得很好。我希望我能给你一个+2我最近运行了一个测试,缓存var sin=Math.sin导致性能下降。也许它不再被认为是x86本机实现的函数?@JanDvorak sin比round重,因此额外的数学查找所造成的极小开销可能微不足道,以至于您无法测量随机性之间的差异。但是函数的实际执行不会改变,因为只有一个实现。哦,正如我在回答中所说的,这是一个微不足道的优化:它不会帮助任何程序,因为你必须进行数百万次调用才能节省几毫秒。如果你想使用Math.sin,谷歌搜索正弦查找表来优化代码。@Mark Yeh所有的答案都证实了你已经相信的。谢谢你提供的额外信息,尽管我应该更好地表述这个问题,以便它更多地关注性能部分,而不是窗口。符号+1。
// Some people use parseInt instead of Math.floor.  This
// optimization makes parseInt on a Smi 12 times faster (60ns
// vs 800ns).  The following optimization makes parseInt on a
// non-Smi number 9 times faster (230ns vs 2070ns).  Together
// they make parseInt on a string 1.4% slower (274ns vs 270ns).
// global code
var var1 = 1, var2 = 2;
(function () { // one
  var var3 = 3;
  (function () { // two
    var var4 = 4;

    with ({var5: 5}) { // three
      alert(var1);
    }
  })();
})();