Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
polyfill an ES5-compatibile Array.isArray where needed.
// only set function if not already available
Array.isArray || (Array.isArray = function(
a // array or not array, this is the question
){
return
// is not the string '[object Array]' and
'' + a !== a &&
// test with Object.prototype.toString
{}.toString.call(a) == '[object Array]'
});
Array.isArray||(Array.isArray=function(a){return''+a!==a&&{}.toString.call(a)=='[object Array]'});
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2011 Alex Kloss <alexthkloss@web.de>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
{
"name": "isarray",
"description": "polyfill an ES5-compatibile Array.isArray where needed.",
"keywords": [
"polyfill",
"es5",
"isArray"
]
}
<!DOCTYPE html>
<title>Foo</title>
<div>Expected value: <b>false, true, false, false, false, false</b></div>
<div>Actual value: <b id="ret"></b></div>
<script>
// write a small example that shows off the API for your example
// and tests it in one fell swoop.
var isArray = Array.isArray||(Array.isArray=function(a){return''+a!==a{}.toString.call(a)=='[object Array]'});
document.getElementById( "ret" ).innerHTML = [isArray({}), isArray([]), isArray(""), isArray(0), isArray(true), isArray('[object Array]')];
</script>
@subzey

This comment has been minimized.

Copy link

@subzey subzey commented Jun 20, 2011

I understand that no one sane will change Object.prototype.toString in runtime in real life. But anyway, it's not a good idea to rely on it.

@atk

This comment has been minimized.

Copy link
Owner Author

@atk atk commented Jun 20, 2011

Thanks for your comment, @subzey

I just ported the function from the ES5-Shim. The only other way to do this I could think of would be "a instanceOf Array". Since it's smaller, too, I think I will update this gist later.

@subzey

This comment has been minimized.

Copy link

@subzey subzey commented Jun 20, 2011

I think instanceof is the best solution.
I tried function(a){return[].concat(a)[0]!=a}. It is very short, but works up to 10 times slower (in node.js) when arg is not array.

@atk

This comment has been minimized.

Copy link
Owner Author

@atk atk commented Jun 20, 2011

Only 1 byte more length anyway, so let's go with the speedier version.

@Kambfhase

This comment has been minimized.

Copy link

@Kambfhase Kambfhase commented Jun 20, 2011

`instanceof´ is the wrong way. This will return false for foreign arrays. ie. arrays from other frames.

@jed

This comment has been minimized.

Copy link

@jed jed commented Jun 20, 2011

what @Kambfhase said. i prefer the original solution.

@atk

This comment has been minimized.

Copy link
Owner Author

@atk atk commented Jun 20, 2011

Changes reverted. Thanks for your comments!

@jed

This comment has been minimized.

Copy link

@jed jed commented Jun 20, 2011

still some room in there:

Array.isArray=Array.isArray||function(a){return toString.call(a)=='[object Array]'}
@atk

This comment has been minimized.

Copy link
Owner Author

@atk atk commented Jun 20, 2011

Alas, the global native function toString is not available in IE6, for example, but ({}).toString is.

@jed

This comment has been minimized.

Copy link

@jed jed commented Jun 20, 2011

ah, didn't know that. you can still shave 3 bytes with the space after return, the triple equality, and the semicolon.

@atk

This comment has been minimized.

Copy link
Owner Author

@atk atk commented Jun 20, 2011

Thanks, done.

@subzey

This comment has been minimized.

Copy link

@subzey subzey commented Jun 20, 2011

@Kambfhase, thanks for your correction!

If the order of operands is reversed we can drop the parens as when interpreter will get {} after == it waits for expression, not block. Either, in that case there's still no need to place whaitespace after return. :)
Array.isArray||Array.isArray=function(a){return'[object Array]'=={}.toString.call(a)}

Also, isn't it better not to assign Array.isArray to itself if it is exists?

@atk

This comment has been minimized.

Copy link
Owner Author

@atk atk commented Jun 20, 2011

{}.toString will lead to a SyntaxError in FF4 (and I guess in other Browsers, too). But the other point is valid. How to do so?
Array.isArray||(Array.isArray=...) seems right, any better ideas?

@jed

This comment has been minimized.

Copy link

@jed jed commented Jun 20, 2011

a.b||(a.b=...)

is definitely a better patten than

a.b=a.b||...

but the latter is shorter. doesn't make much of a difference here, but for Array.prototype.map it does. i'd rather have all shims be consistent, personally, but i guess it's a style thing.

@subzey

This comment has been minimized.

Copy link

@subzey subzey commented Jun 20, 2011

@atk, that's strange. It works fine in my Fx 4.0.1

@atk

This comment has been minimized.

Copy link
Owner Author

@atk atk commented Jun 20, 2011

Strange enough, if I put it directly into my firebug console, it fails - but if I encapsulate it into a function, it works! Thanks again, @subzey

@sebastien-p

This comment has been minimized.

Copy link

@sebastien-p sebastien-p commented Jul 8, 2011

What about Array.isArray||(Array.isArray=function(a){return/Array/.test({}.toString.call(a))}) ?

@subzey

This comment has been minimized.

Copy link

@subzey subzey commented Jul 8, 2011

@sebastien-p, It may conflict with typed arrays.

@sebastien-p

This comment has been minimized.

Copy link

@sebastien-p sebastien-p commented Jul 8, 2011

@subzey : ok, thanks :)

@atk

This comment has been minimized.

Copy link
Owner Author

@atk atk commented Jul 8, 2011

Not even that, what if I want to test a string containing "Array" at any point. Granted, if you try a string containing "[object Array]" it will return a false positive, too, yet this is less problematic, so if you want to be sure, add &&''+a!==a.

@subzey

This comment has been minimized.

Copy link

@subzey subzey commented Mar 9, 2012

Maybe we could use the behavior of Array.prototype.concat so interpreter natively checks if argument is an array

Array.isArray?0:Array.isArray=function(a){return[].concat(a)!==a}
@atk

This comment has been minimized.

Copy link
Owner Author

@atk atk commented Mar 9, 2012

@subzey
(function(a){return[].concat(a)!==a})('') // => true in firefox 10

@subzey

This comment has been minimized.

Copy link

@subzey subzey commented Mar 10, 2012

Thanks, @atk!

Sorry, I missed [0]. That what I meant was

function(a){return[].concat(a)[0]!==a}

Array.prototype.concat adds argument's contents to this array if arg is an array and otherwise it adds the argument itself.

I wanted to exploit this difference, but lately I've found an error: it won't work correctly if argument is an array and its 0'th value is the same object (var a = []; a[0] = a).

@atk

This comment has been minimized.

Copy link
Owner Author

@atk atk commented Mar 12, 2012

Ah, that explains it.

@atk

This comment has been minimized.

Copy link
Owner Author

@atk atk commented Apr 12, 2012

Added another fix. If you tried to test the format of '[object Array]', it would give you a false positive; by ensuring that we haven't got a string, this is now fixed, too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment