2

I have been adding an Array.indexOf() polyfill to the main JavaScript file of our project. I took it from devdocs.io:

if (!Array.prototype.indexOf) {
  Array.prototype.indexOf = function (searchElement , fromIndex) {
    var i,
        pivot = (fromIndex) ? fromIndex : 0,
        length;

    if (!this) {
      throw new TypeError();
    } 

    length = this.length;

    if (length === 0 || pivot >= length) {
      return -1;
    }

    if (pivot < 0) {
      pivot = length - Math.abs(pivot);
    }

    for (i = pivot; i < length; i++) {
      if (this[i] === searchElement) {
        return i;
      }
    }
    return -1;
  };
}

I need this because we still have to support IE 8, but it seems that in IE 8, the indexOf() function is added enumerable. That means, it appears when iterating over arrays using for..in loops, like this:

var a = [];
a[0]=123;
a[1]=456;
for(var value in a) {
    alert(value); // this even alerts "indexOf", if the polyfill above is loaded, and this is a big problem
}

Is it possible to make the polyfill "unenumerable", so that I am able to use Array.indexOf() in IE 8, but it does not appear in for..in loops?

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
Paul H
  • 600
  • 1
  • 5
  • 13
  • 7
    I think for ... in ... is not a good idea with arrays: http://stackoverflow.com/questions/500504/why-is-using-for-in-with-array-iteration-such-a-bad-idea – Pablo Lozano Jan 16 '14 at 15:17
  • 2
    The solution here is to stop using `for...in` to iterate an Array. Use a simple `for` loop instead. – André Dion Jan 16 '14 at 15:18
  • I can not change the fact that there are hundreds of for..in loops over Arrays in our Code. It would be immense work to change them all. The polyfill though, has not been in the code so long and it would be relatively easy to remove it... If there is no other way I will have to do that. – Paul H Jan 16 '14 at 15:23
  • @PaulMa Is moving the code outside the Array.prototype acceptable? This includes calling it differently. – Tibos Jan 16 '14 at 15:40
  • I've been discussing this with my colleagues, and we decided that we really want to leave the polyfill as it is, and we will check the result of the hasOwnProperty function in every for-in loop. Thanks for your help! – Paul H Jan 17 '14 at 11:53

3 Answers3

3

Generally speaking, you can add a property as non-enumerable using Object.defineProperty:

Object.defineProperty(Array.prototytpe, 'indexOf', {
  enumerable : false,
  value : function(){ /* my polyfill code */}
});

But, as you've probably guessed, there is no support for it in IE8, so you're stuck with @tkone's solution of filtering the for..in with hasOwnProperty.


Another pseudo-solution is to create a function you pass the array parameter to:

function indexOf(array, searchElement, fromIndex) {
  if (Array.prototype.indexOf) return array.indexOf(searchElement, fromIndex);
  /* my polyfill code with array instead of this*/
}

and simply use that instead of the native indexOf:

[1,2,3].indexOf(2); // change to:
indexOf([1,2,3], 2);

You could namespace your function as well so you remember to change it back to standards when you no longer bother with IE8:

IhateIE8.indexOf = ...
Tibos
  • 27,507
  • 4
  • 50
  • 64
1

You should be using hasOwnProperty when you enumerate over the members of an object.

var a = [];
a[0] = 123;
a[1] = 456;
for(var value in a){
    if(a.hasOwnProperty(value)){
        alert(value);
    }
}

But why aren't you just doing a simple for loop (or polyfilling something like forEach)

tkone
  • 22,092
  • 5
  • 54
  • 78
  • For the record: The jshint option is called `forin` to prevent for..in loops without this check. – Prinzhorn Jan 16 '14 at 15:21
  • See my comment above. We can not implement this for every for..in loop in our code. I either will have to remove the polyfill or make it unenumberable. – Paul H Jan 16 '14 at 15:25
  • Well, first, you should probably refactor your codebase. Using `for...in` for array enumeration is a really bad idea because of the enumerable issues. Second, you can. It's called a search and replace using a regex. :) – tkone Jan 16 '14 at 15:27
  • @PaulMa also, if that is the case then it is impossible to do what you are asking. IE8 does not support the concept of the enumerable flag. – tkone Jan 16 '14 at 15:28
0

Is it possible to make the polyfill "unenumerable", so that I am able to use Array.indexOf() in IE 8, but it does not appear in for..in loops?

Officially, yes (see defineProperty and enumerable), but specifically for IE8 and lower, not really.

I don't think it's a good idea though (see the comments).

Kos
  • 70,399
  • 25
  • 169
  • 233