代码之家  ›  专栏  ›  技术社区  ›  Mark Rogers

在javascript中,访问“window.math”的速度是否比访问不带“window”的“math”对象慢或快?

  •  5
  • Mark Rogers  · 技术社区  · 15 年前

    我有点好奇在javascript中引用“global”名称空间时的最佳实践是什么,它只是 window 对象(或副韵文,取决于你如何看待它)。

    我想知道:

    var answer = Math.floor(value);
    

    好于或坏于:

    var answer = window.Math.floor(value);
    

    在性能、资源使用或兼容性方面是好是坏?

    有没有更高的成本?(像一个额外的指针之类的东西)

    编辑注释 :虽然在大多数情况下,我是一个比性能纳粹可读性,但在这种情况下,我忽略了仅仅关注性能的可读性差异。

    6 回复  |  直到 15 年前
        1
  •  14
  •   Blixt    15 年前

    首先,不要因为性能原因而比较类似的东西。 Math.round 显然眼睛比 window.Math.round 如果使用其中一个或另一个,您将看不到显著的性能提高。因此,不要为性能的微小提高而混淆代码。

    但是,如果你只是好奇哪一个更快…我不确定全球范围是如何被“隐藏”起来的,但我想访问 window 与访问相同 Math ( 窗口 数学 生活在同一个水平上,如 window.window.window.Math.round 工作)。因此,访问 window.Math 会变慢。

    此外,通过查找变量的方式,您可以看到通过执行 var round = Math.round; 呼唤 round(1.23) ,因为所有名称首先在当前本地作用域中查找,然后在当前作用域之上查找,依此类推,一直到全局作用域。每个范围级别都增加了非常小的开销。

    但同样,不要进行这些优化,除非您确定它们会产生显著的差异。可读、可理解的代码对于它现在和将来的工作方式很重要。

    以下是使用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>
    

    我的结果是:
    Time 显示100000*10个呼叫的总数, Avg / Min / Max 显示100000次通话的时间。

    Calls  Percent  Own Time   Time       Avg        Min        Max
    bench_window_Math_round
    10     86.36%   1114.73ms  1114.73ms  111.473ms  110.827ms  114.018ms   
    bench_Math_round
    10      8.21%    106.04ms   106.04ms   10.604ms   10.252ms   13.446ms   
    bench_round
    10      5.43%     70.08ms    70.08ms    7.008ms    6.884ms    7.092ms
    

    正如你所看到的, 数学窗口 真是个坏主意。我想访问全球 窗口 对象增加了额外的开销。但是,访问 数学 对象,只访问引用 数学回合 功能不是很好…请记住,这是100000个呼叫,而差异仅为3.6毫秒。即使有一百万个呼叫,您也只能看到36毫秒的差异。

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

    • 实际上,这些函数是从另一个作用域中查找的,这增加了开销(尽管我尝试将这些函数导入匿名函数,但几乎没有注意到)。
    • 实际 数学回合 函数增加了开销(我猜在100000个调用中大约有6ms)。
        2
  •  2
  •   Mahmoud Al-Qudsi    15 年前

    不同浏览器的JS性能差异很大。

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

        3
  •  2
  •   Christian C. Salvadó    15 年前

    如果你想知道 Scope Chain and the Identifier Resolution 工艺工作。

    作用域链是在评估标识符时搜索的对象列表,这些对象不能被代码访问,只能访问其属性(标识符)。

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

    在函数执行上下文中输入时,将创建链中的后续对象,并通过 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);
        }
      })();
    })();
    

    在上面的代码中,作用域链将包含不同级别的不同对象,例如,在最低级别,在 具有 声明,如果使用 var1 var2 变量,作用域链将包含4个需要检查的对象,以便获得该标识符:由 具有 语句,两个函数,最后是全局对象。

    你也需要知道 window 只是一种财产 存在于全局对象中的 指向全局对象本身 . 窗口 是由浏览器引入的,在其他环境中通常不可用。

    总之,当你使用 窗口 ,因为它只是一个标识符(不是保留字或类似的东西),需要通过所有的解析过程才能获得全局对象, window.Math 需要由DOT执行的附加步骤( . )属性访问器。

        4
  •  1
  •   Chris S    15 年前

    (如你所说) Math.floor 可能只是一个捷径 window.Math (AS) window 是一个javascript全局对象)在大多数javascript实现中,如V8。

    蜘蛛猴和V8将非常适合普通的使用,所以它不应该成为一个问题。

    对于可读性,我的偏好是使用 数学地板 速度上的差别是如此之小,根本不值得担心。如果你的楼层是100000层,那么可能是时候把这个逻辑从客户机中切换出来了。

    你可能想了解一下V8的源代码,这里有一些有趣的评论,关于削掉纳秒的函数,比如 this int.Parse() 一个。

    // 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).
    
        5
  •  1
  •   naivists    15 年前

    就我所理解的javascript逻辑而言,您所指的一切 something 在全局变量范围内搜索。在浏览器实现中, window 对象 全局对象。因此,当你要求 window.Math 实际上你必须去参考什么 窗口 意思是,然后得到它的属性并找到 Math 在那里。如果你只是要求 数学 首先是全局对象。

    所以,是的-打电话 Math.something 会比 window.Math.something .

    D.克罗克福德在他的演讲中谈到了这一点。 http://video.yahoo.com/watch/111593/1710507 据我所知,它在视频的第三部分。

        6
  •  0
  •   leepowers    15 年前

    如果 Math.round() 在本地/函数范围内调用时,解释器必须先检查本地var,然后检查全局/窗口空间。所以在地方范围内,我想应该是 window.Math.round() 会稍微快一点。这不是程序集,也不是C或C++,所以我不会担心哪个更快。 性能 原因,但如果出于好奇,当然,要做基准。