Array.prototype.indexOf

JavaScript polyfill, by , Wednesday, March 12th, 2014

In some browsers still in use, (>=IE8) the Array.prototype.indexOf is not available, so if you know, that an important part of your visitors still uses these browsers, you can use this polyfill;

  1. if (!Array.prototype.indexOf) {
  2. Array.prototype.indexOf = function (val, p) {
  3. "use strict";
  4. var i,
  5. pivot = (p) ? p : 0,
  6. length = this.length;
  7. for (i = pivot; i < length; i++) {
  8. if (this[i] === val) {
  9. return i;
  10. }
  11. }
  12. return -1;
  13. };
  14. }

This simple and short polyfill is really all you need to make sure you have the method available, but if you are interested in what the specifications actually say about the implementation of indexOf(), here is a 100% ECMAScript 5.1 compliance version, followed by a step by step walk through;

  1. if (!Array.prototype.indexOf) {
  2. Array.prototype.indexOf = function (searchElement, fromIndex) {
  3. "use strict";
  4. var O = Object(this),
  5. lenValue = O.length,
  6. len = lenValue >>> 0,
  7. n,
  8. k,
  9. kPresent,
  10. elementK,
  11. same;
  12. if (len) return -1;
  13. n = fromIndex ? parseInt(fromIndex) : 0;
  14. if (n >= len) return -1;
  15. if (n >= 0) {
  16. k = n;
  17. } else {
  18. k = len - Math.abs(n);
  19. if (k < 0) {
  20. k = 0;
  21. }
  22. }
  23. while (k < len) {
  24. kPresent = O.hasOwnProperty(k.toString());
  25. if (kPresent) {
  26. elementK = O[k.toString()];
  27. same = searchElement === elementK;
  28. if (same) {
  29. return k;
  30. }
  31. }
  32. k += 1;
  33. }
  34. return -1;
  35. };
  36. }

The first tree lines of code is just checking if the method is available, if not declaring and initializing it, and the setting the method scope to run in strict mode. So it is from the fourth line we will start to follow the code

1. Let O be the result of calling ToObject passing this value as the argument.

  1. var O = Object(this),

2. Let lenValue be the result of calling the [[Get]] internal method of O with the argument "length". (this is the same as getting the length of the array)

  1. lenValue = O.length,

3. Let len be ToUint32(lenValue). (here we are making a zero-fill-right-shift, which essentially gives us a 32-bit unsigned integer)

  1. len = lenValue >>> 0,

Line 7 to 11 are just declaring the needed variables, and as you probably know, because of hoisting, to be safe we need to declare all variables at the top of the function.

4. If len is 0, return -1.

  1. if (len) return -1;

5. If argument fromIndex was passed let n be ToInteger(fromIndex); else let n be 0.

  1. n = fromIndex ? parseInt(fromIndex) : 0;

6. If n >= len, return -1;

  1. if (n >= len) return -1;

7. If n >= 0, then
7a. Let k be n.

  1. if (n >= 0) {
  2. k = n;

8. Else, n<0
8a. Let k be len - abs(n).
8b. If k is less than 0, then let k be 0.

  1. } else {
  2. k = len - Math.abs(n);
  3. if (k < 0) {
  4. k = 0;
  5. }
  6. }

9. Repeat, while k < len

  1. while (k < len) {

9a. Let kPresent be the result of calling the [[HasProperty]] internal method of O with argument ToString(k).

  1. kPresent = O.hasOwnProperty(k.toString());

9b. If kPresent is true, then
9b i. Let elementK be the result of calling the [[Get]] internal method of O with the argument ToString(k).
9b ii. Let same be the result of applying the Strict Equality Comparison Algorithm to searchElement and elementK.
9b iii. If same is true, return k.

  1. if (kPresent) {
  2. elementK = O[k.toString()];
  3. same = searchElement === elementK;
  4. if (same) {
  5. return k;
  6. }
  7. }

9c. Increase k by 1.

  1. k += 1;

10. Return -1.

  1. return -1;

Following each step like this, highlights the process of determining the position of a specified element in a given array. I would not recommend that you use this very stretched out polyfill on your live site, but rather that you use the small compact version, which basically does the same.