Brett Zamir
Brett Zamir

Reputation: 14355

Array.prototype.slice shim for non-arrays in older Internet Explorers

I am interested in finding or writing a pseudo-shim to allow Array.prototype.slice to support non-arrays (while working in the same manner across browsers).

I know there are interfaces like NamedNodeMap, HTMLCollection, etc. which can be converted, e.g., in Firefox but not in IE <= 8.

Two questions:

  1. Does IE indeed not work with the arguments object as some people have said? (I only have IE 10 installed, and it works fine even in IE5 quirks/IE7 mode (and it is fine with a hand-made array-like object as well).)
  2. What kind of duck-typing or such could I use to comprehensively support all of the non-array types supported in some browsers when applied with Array.prototype.slice.call()? For example, I might duck-type for item as a function and try to get a valid value back when supplying a sample number like 0. Firefox and IE8 both accept length even as strings (parsed into an integer). Will browsers like Firefox similarly work with any DOM object as long as it has a length property?

Upvotes: 3

Views: 1856

Answers (1)

jfriend00
jfriend00

Reputation: 707886

Here's a recently asked and related question that caused this older question to get rediscovered.

There's a polyfill for Array.prototype.slice() here on the MDN page for .slice() that will work with all browsers for making a copy of any array-like object. Since, this polyfill is only needed for older versions of IE, the polyfill starts with a specific test for something that fails in older versions of IE (thus it only installs itself when needed).

try {
    // Can't be used with DOM elements in IE < 9
    _slice.call(document.documentElement);
} catch (e) {
    // we know we're in IE < 9 here
}

The polyfill, then uses the standard test to see if the object is a real array:

// test if this is an actual array
if (Object.prototype.toString.call(this) === '[object Array]')

So, on real arrays, the regular built-in .slice() is used. The polyfill then goes on to implement it's own copy function by just using .length and [index] for reading content which are safe on any array-like object and it returns the contents copied into a new array.


To your specific questions:

Does IE indeed not work with the arguments object as some people have said? (I only have IE 10 installed, and it works fine even in IE5 quirks/IE7 mode (and it is fine with a hand-made array-like object as well).)

The arguments object is a native Javascript array-like object (not a host object and not a real array) so there are no particular quirks with making a copy of it. There are some new restrictions added to the arguments object in strict mode, but one can still make a copy of it. The usual way to make a copy of the arguments object that works in all browsers is:

var items = Array.prototype.slice.call(arguments, 0);

One has to use Array.prototype.slice because the arguments object itself is not an array and does not have array methods on it.

What kind of duck-typing or such could I use to comprehensively support all of the non-array types supported in some browsers when applied with Array.prototype.slice.call()? For example, I might duck-type for item as a function and try to get a valid value back when supplying a sample number like 0. Firefox and IE8 both accept length even as strings (parsed into an integer). Will browsers like Firefox similarly work with any DOM object as long as it has a length property?

Object.prototype.toString.call(this) === '[object Array]' is the foolproof way to test if something is an actual array. I'm not aware of any duck-typing method to see if something is an array-like object other than testing to see if the object has a .length property and if you can use [index] to read values without causing an exception.

If you want to work on as many older browsers as possible and as many types of non-array objects as possible, then I'd suggest you use the above linked polyfill on the MDN page as that is what it is specifically designed for.

Since the world is (finally) starting to move beyond the older versions of IE, if you can now live with only supporting IE9 and above, then you can the Array.prototype.slice.call() method on all array-like objects (anything that has a .length property that corresponds to how many items there are that can be accessed with integer indexes via [i] and you won't even need the polyfill.

Upvotes: 3

Related Questions