3

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?

8
  • 2
    Don't do that. Use a regular for loop. Commented May 8, 2015 at 18:58
  • Yea, that would work, except I'm retrofitting this onto a large project so going back and changing all of the array code is painful. It also wouldn't suffice for the associative arrays (hacked dictionaries) that some of the code uses. Commented May 8, 2015 at 19:00
  • 2
    Associative arrays should be objects, not arrays. Commented May 8, 2015 at 19:01
  • 3
    That should be an object, not an array. Commented May 8, 2015 at 19:02
  • 2
    Just FYI - in case you wrote this yourself from scratch, you can get this and many polyfills from MDN: Array.prototype.indexOf() Polyfill Commented May 8, 2015 at 19:21

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

Comments

2

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 = [];

2 Comments

yea, I was just showing an example. I know better than to scope globally
@jugg1es Cool then :-) Most of us miss that during the coding and review phase, and since the code works fine, we will discover it only when we face weird issues.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.