jugg1es
jugg1es

Reputation: 1600

Issue extending Array in IE8

So IE8 doesn't support Array.indexOf(), so I copied some code that extends the Array prototype so that it is supported and it works.

if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function (elt /*, from*/) {
        var len = this.length >>> 0;

        var from = Number(arguments[1]) || 0;
        from = (from < 0)
             ? Math.ceil(from)
             : Math.floor(from);
        if (from < 0)
            from += len;

        for (; from < len; from++) {
            if (from in this &&
                this[from] === elt)
                return from;
        }
        return -1;
    };
}

However, I'm running into an issue when I iterate over an array now. Take this for example:

arrayObject = [];
//do some stuff
for(var i in arrayObject) {
  ...
}

The problem is that after extending the Array prototype, one of the values for i above is now equal to indexOf, and the value at that index (i.e. arrayObj[i]) is equal to the contents of the function. This happens even when the length of the array is zero!! So even when the array is empty, it's still iterating once through for the indexOf entry.

I realize that I can simply do some type checking in the loop, but I'd rather not do that because I'm retrofitting fallback compatibility onto a large existing project. Is there a way to have the indexOf array functionality in IE8 without running into this issue?

Upvotes: 3

Views: 86

Answers (2)

thefourtheye
thefourtheye

Reputation: 239683

If at all, you have to use only for..in to iterate the array, just check if the current item is defined in the Array object, with Object.hasOwnProperty, like this

var arrayObject = [];

for(var i in arrayObject) {
    if (arrayObject.hasOwnProperty(i)) {
      ...
    }
}

Note: As per MSDN's documentation of hasOwnProperty, it is supported in Internet Explorer 8 Standards mode.


The proper way to define indexOf would be to make in non-enumerable, like this

Object.defineProperty(Array.prototype, 'indexOf', {
    enumerable: false,
    configurable: false,
    writable: false,
    value: function polyFillIndexOf() {...}
});

Since we defined it as non-enumerable, for..in loop, will not pick the indexOf property. So, you can still use for..in with the Array objects (though it is not recommended to do so).

But unfortunately, as per MSDN's documentation of Object.defineProperty, it works only with DOM objects in IE-8.


Apart from this, when you use for..in with an Array, you might run in to this inconsistent order of keys problem mentioned in MDN,

Array indexes are just enumerable properties with integer names and are otherwise identical to general Object properties. There is no guarantee that for...in will return the indexes in any particular order and it will return all enumerable properties, including those with non–integer names and those that are inherited.

Because the order of iteration is implementation dependent, iterating over an array may not visit elements in a consistent order. Therefore it is better to use a for loop with a numeric index (or Array.prototype.forEach() or the for...of loop) when iterating over arrays where the order of access is important.


So, the simplest and the best way to do this would be, using simple for loop, with numeric array indexes, like this

for(var i = 0; i < arrayObject.length; i++) {
    console.log(arrayObject[i]);
}

or using Array.prototype.forEach (which is also supported in Internet Explorer 8 Standards mode), like this

arrayObject.forEach(function(currentItem) {
    ...
});

PS: Be careful with

arrayObject = [];

you are actually creating a global variable called arrayObject. You might want to use the var keyword, like this

var arrayObject = [];

Upvotes: 2

ShaneQful
ShaneQful

Reputation: 2236

You can use hasOwnProperty to make sure that the i is an index of the array and not a function like indexOf.

for (var i in arrayObject) {
  if( arrayObject.hasOwnProperty( i ) ) {
    //...
  } 
}

See docs below for more info:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in

That said I'd probably recommend using a counter e.g.

for(var i = 0; i < arrayObject.length; i++) {}

or an each method from a framework like underscore, dojo or jquery etc.. than using a for..in loop like this.

Upvotes: 2

Related Questions