The conclusion was, to use typeof for any "global" variable and a direct conditional check against undefined within the scope of a function where you know the variables are at least declared. That makes sense, because if( some_undefined_variable !== undefined ) throws a reference error.
I played around with that in mind and I thought, this might be interesting for fellow Javascripters. My first testcase looked like this:
var loops = 1e6, foo; console.time('typeof'); while(loops--) { if( typeof foo !== 'undefined' ) {} } console.timeEnd('typeof'); loops = 1e6; console.time('direct'); while(loops--) { if( foo !== undefined) {} } console.timeEnd('direct');
with the result of:
typeof: 421ms direct: 603ms
Pretty interesting. So here it looks like, typeof is faster than just comparing a variable against undefined. I couldn't really believe what I've seen here. I thought that is probably because I'm in the global context and my Javascript engine (SpiderMonkey) does some kind of wierd scope chain lookups for "undefined". Anyway, it should improve the overall performance to put that code into a function (-context), which I did:
(function() { var loops = 1e6, foo; console.time('typeof'); while(loops--) { if( typeof foo !== 'undefined' ) {} } console.timeEnd('typeof'); loops = 1e6; console.time('direct'); while(loops--) { if( foo !== undefined) {} } console.timeEnd('direct'); }());
Results:
typeof: 54ms direct: 185ms
As expected, this has a better overall performance, but still typeof is way faster than a plain conditional check vs. undefined. Well, the important thing I forgot here is to keep a local reference (some people call it: cache) for the undefined value:
(function(undef) { var loops = 1e6, foo; console.time('typeof'); while(loops--) { if( typeof foo !== 'undefined' ) {} } console.timeEnd('typeof'); loops = 1e6; console.time('direct'); while(loops--) { if( foo !== undef) {} } console.timeEnd('direct'); }());
Final results:
typeof: 51ms direct: 38ms
Yay! That's the way to go and that's why you always should try to cache objects / object propertys before accessing (if its not a problem to have a static reference).
My default Javascript opener when using jQuery looks like:
(function(win, doc, $, undef) { // lots of beautiful code that can access win(window), // doc(document), $(jQuery) and undef(undefined) }(this, this.document, jQuery));
However, to be honest I'm still not 100% sure why this affects the undefined value that much. Cached references are faster to access (fact), totally makes sense for objects and propertys, but the undefined value is not a property as far as I know.
update:
I was wrong. undefined really is a property in the global object (window).
'undefined' in window; // = true
This explains why the cached version of the undefined value is way faster. Thanks to Stackoverflow member CMS who pointed me on this fact here.
sorry for the improper comment, but 1e6 is a pretty neat shortcut.
ReplyDeleteScript against right-click on a blog speaking on good programming... Defeat all author's credibility, don't you think ?
ReplyDeleteCtrl+C Ctrl+V
ReplyDeleteIf I run the code outside the console, I get the following results:
ReplyDeletefirefox (with 1e7):
global context
typeof: 228
equals : 205
function context
typeof: 121
equals : 94
chrome (with 1e8):
global context
typeof: 235
equals : 202
function context
typeof: 129
equals : 102
So equals seems actually faster.
Example code:
var benchmark = function() {
var initloops = 1e7, foo, loops = initloops, t0, t1;
t0 = Date.now();
while(loops--) { if( typeof foo === 'undefined' ) {} }
t1 = Date.now();
console.log('typeof: ' + (t1-t0));
loops = initloops;
t0 = Date.now();
while(loops--) { if( foo === undefined) {} }
t1 = Date.now();
console.log('equals : ' + (t1-t0));
};
var s = document.createElement('script');
var code = benchmark.toString().split('\n');
var glob = "console.log('global context');\n" + code.slice(1,code.length-1).join('\n');
var clos = "console.log('function context');\n(" + code.join('\n') + '());';
s.textContent = glob + '\n' + clos;
document.head.appendChild(s);
I haven't tried yet but I guess in 2011 browser implementation is not as fast as now (2015).
DeleteHave you tried "1e6" and "1e5" ? If the result is different , it may have something to do with the "scale" then ;-)
bro dont know what he talkin about lmfaoooo
Deletethank you. I was looking for this
ReplyDeleteRespect and I have a tremendous offer you: When Home Renovation whole home remodel cost
ReplyDeleteGreat reading your blog postt
ReplyDelete