Tuesday, September 14, 2010

isArray, optimized ?

isArray optimized ?

The world has almost agreed that this is
correct check for Array in JavaScript.

var toString = Object.prototype.toString,
isArray: function(obj) {
return toString.call(obj) === "[object Array]";
};

Similar checks are used for Date or Numbers.
For those who may not know why, read this excelent explanation by kangax:

instanceof considered harmful (or how to write a robust isArray)


I have been curios about performance:

100 000 loops !!! times in mils compare native naive checks and the correct one.

MSIE 7.0
a instanceof Array 63:true
a.constructor === Array 62:true
toString.call(a) == [object Array] 235:true

Firefox/3.5.12
a instanceof Array 12:true
a.constructor === Array 41:true
toString.call(a) == [object Array] 51:true

Safari/533.18.5
a instanceof Array 2:true
a.constructor === Array 5:true
toString.call(a) == [object Array] 41:true

MSIE 7.0 is the slowest and penalty is >4 all browsers.

Again this is of course nothing in absolute numbers,
since we are talking about 100000 loops here !

Speedup for false checks

The penalty and measured times are "the same"
even if you pass null or undefined inside.

Since I use this method
often on attribute normalization
at the begining of my functions,
and many times the checked attribute is optional
(null, undefined or even "")

I propose small speed up with this code:

var toString = Object.prototype.toString,
isArray: function(obj) {
return (object!=null && toString.call(obj) === "[object Array]");
};

Yes the "evel twin" is intentional.
or even with

var toString = Object.prototype.toString,
isArray: function(obj) {
return (!!object && toString.call(obj) === "[object Array]");
};

Of course you pay some extra penalty for this (20ms/100000 loops on MSIE) in positive checks,
but it drops down false checks to almost no cost (31ms/100000 loops).
BTW do we need === to compare strings ?
Benchmarks:

arrLit toString.call(a) == [object Array] 219:true:[object Array]
arrLit optimized toString.call(a) 234:true:[object Array]

null toString.call(a) == [object Array] 203:false:[object Object]
null optimized toString.call(a) 31:false:[object Object]

You see the extra price on positive call 219 vs 234 and spped up 203 vs 31!
on null input

Of course you can still write the code outside of isArray
in each code where it makes sence
but I like it inside - optimized.

I see no sence to let null be converted to
[object Window] (on FF) and compared as string with [Object Array].

No comments:

Post a Comment