Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In javascript, is accessing 'window.Math' slower or faster than accessing the 'Math' object without the 'window.'?

I'm kind of curious about what the best practice is when referencing the 'global' namespace in javascript, which is merely a shortcut to the window object (or vice versia depending on how you look at it).

I want to know if:

var answer = Math.floor(value);

is better or worse than:

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

Is one better or worse, even slightly, for performance, resource usage, or compatibility?

Does one have a slighter higher cost? (Something like an extra pointer or something)

Edit note: While I am a readability over performance nazi in most situations, in this case I am ignoring the differences in readability to focus solely on performance.

like image 645
Mark Rogers Avatar asked Jan 23 '10 23:01

Mark Rogers


People also ask

Why window is used in JavaScript?

For example, you can use Windows to browse the Internet, check your email, edit digital photos, listen to music, play games, and do much more. Windows is also used in many offices because it gives you access to productivity tools such as calendars, word processors, and spreadsheets.

Is Math Floor slow?

The primary reason Math. floor is slower (where it actually is--in some tests I've done it's faster) is that it involves a function call.

What is math object in JavaScript?

The math object provides you properties and methods for mathematical constants and functions. Unlike other global objects, Math is not a constructor. All the properties and methods of Math are static and can be called by using Math as an object without creating it.


4 Answers

First of all, never compare things like these for performance reasons. Math.round is obviously easier on the eyes than window.Math.round, and you wouldn't see a noticeable performance increase by using one or the other. So don't obfuscate your code for very slight performance increases.

However, if you're just curious about which one is faster... I'm not sure how the global scope is looked up "under the hood", but I would guess that accessing window is just the same as accessing Math (window and Math live on the same level, as evidenced by window.window.window.Math.round working). Thus, accessing window.Math would be slower.

Also, the way variables are looked up, you would see a performance increase by doing var round = Math.round; and calling round(1.23), since all names are first looked up in the current local scope, then the scope above the current one, and so on, all the way up to the global scope. Every scope level adds a very slight overhead.

But again, don't do these optimizations unless you're sure they will make a noticeable difference. Readable, understandable code is important for it to work the way it should, now and in the future.

Here's a full profiling using 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>

My results:
Time shows total for 100,000 * 10 calls, Avg/Min/Max show time for 100,000 calls.

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

As you can see, window.Math is a really bad idea. I guess accessing the global window object adds additional overhead. However, the difference between accessing the Math object from the global scope, and just accessing a local variable with a reference to the Math.round function isn't very great... Keep in mind that this is 100,000 calls, and the difference is only 3.6ms. Even with one million calls you'd only see a 36ms difference.

Things to think about with the above profiling code:

  • The functions are actually looked up from another scope, which adds overhead (barely noticable though, I tried importing the functions into the anonymous function).
  • The actual Math.round function adds overhead (I'm guessing about 6ms in 100,000 calls).
like image 155
Blixt Avatar answered Oct 05 '22 00:10

Blixt


This can be an interest question if you want to know how the Scope Chain and the Identifier Resolution process works.

The scope chain is a list of objects that are searched when evaluating an identifier, those objects are not accessible by code, only its properties (identifiers) can be accessed.

At first, in global code, the scope chain is created and initialised to contain only the global object.

The subsequent objects in the chain are created when you enter in function execution context and by the with statement and catch clause, both also introduce objects into the chain.

For example:

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

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

In the above code, the scope chain will contain different objects in different levels, for example, at the lowest level, within the with statement, if you use the var1 or var2 variables, the scope chain will contain 4 objects that will be needed to inspect in order to get that identifier: the one introduced by the with statement, the two functions, and finally the global object.

You also need to know that window is just a property that exists in the global object and it points to the global object itself. window is introduced by browsers, and in other environments often it isn't available.

In conclusion, when you use window, since it is just an identifier (is not a reserved word or anything like that) and it needs to pass all the resolution process in order to get the global object, window.Math needs an additional step that is made by the dot (.) property accessor.

like image 27
Christian C. Salvadó Avatar answered Oct 04 '22 23:10

Christian C. Salvadó


JS performance differs widely from browser to browser.

My advice: benchmark it. Just put it in a for loop, let it run a few million times, and time it.... see what you get. Be sure to share your results!

like image 29
Mahmoud Al-Qudsi Avatar answered Oct 04 '22 23:10

Mahmoud Al-Qudsi


(As you've said) Math.floor will probably just be a shortcut for window.Math (as window is a Javascript global object) in most Javascript implementations such as V8.

Spidermonkey and V8 will be so heavily optimised for common usage that it shouldn't be a concern.

For readability my preference would be to use Math.floor, the difference in speed will be so insignificant it's not worth worrying about ever. If you're doing a 100,000 floors it's probably time to switch that logic out of the client.

You may want to have a nose around the v8 source there's some interesting comments there about shaving nanoseconds off functions such as this int.Parse() one.

// 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).
like image 36
Chris S Avatar answered Oct 05 '22 00:10

Chris S