Array Expansion Issue in IE8

So IE8 doesn't support Array.indexOf()

, so I copied some code that extends the Array prototype to be 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 ran into a problem when I now iterate over the array. 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 indexOf

, and the value at that index (i.e. arrayObj[i]

) is equal to the content of the function.This happens even when the length of the array is zero! Therefore, even when the array is empty, it is still iterated over for writing indexOf

.

I realize that I can just do some type checking in a loop, but I would rather not do this because I am upgrading fallback compatibility with a large existing project. Is there a way to have array functionality indexOf

in IE8 without facing this issue?

+3


source to share


2 answers


You can use hasOwnProperty to make sure i is an array index and not an indexOf function.

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

      

See docs below for more information:

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



This says that I probably recommend using a counter for example.

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

      

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

+2


source


If you only need to use for..in

to iterate over an array at all, just check if the current element is defined in the Array object, with Object.hasOwnProperty

like this

var arrayObject = [];

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

      

Note. ... According to MSDN documentationhasOwnProperty

, it is supported in Internet Explorer 8 Standards mode.


The correct way to define indexOf

should be in a non-enumerable form, for example

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

      

Since we have defined it as a non-enumerable loop for..in

, it will not select a property indexOf

. This way you can still use for..in

with Array objects (although not recommended).

But unfortunately, according to the MSDN documentationObject.defineProperty

, it only works with DOM objects in IE-8.


Also, when you use for..in

with an array, you can run this inconsistent key order mentioned in MDN ,

Array indices are simply enumerated properties with integer names and are otherwise identical to general object properties. There is no guarantee that it for...in

will return indexes in any particular order and will return all enumerated properties, including those with non-integer names and inheritance.

Since the order of iteration is implementation dependent, iterating over an array may not visit the elements in sequential order. Therefore, it is better to use a for loop with a numeric index (or Array.prototype.forEach()

or loop for...of

) when iterating over arrays where the sequence of access is important.




So, the simplest and best way to do it is to use a simple loop for

with numeric array indices, like

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

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

      


PS: Be careful with

arrayObject = [];

      

you are actually creating a global variable named arrayObject

. You might want to use a keyword var

like

var arrayObject = [];

      

+2


source







All Articles