JavaScript Promises in Depth

ES2015 brought a native Promise implementation to the JavaScript standard library. In this course, we’re going to take an in-depth look at how to use promises to model asynchronous operations in JavaScript.

Watch the Course

ECMAScript 2016: Array.prototype.includes()

The Array.prototype.includes() method is one of the two new features that ECMAScript 2016 standardizes. It determines whether an array contains a given element and returns either true or false.

The other new feature is the exponentiation operator **, which provides a little syntactic sugar for Math.pow.

Egghead Lesson: Check If an Array Contains an Item Using Array.prototype.includes

Array.prototype.includes vs. Array.prototype.indexOf

Up until now, you've probably compared the return value of the Array.prototype.indexOf method against -1 to check whether an array contains a certain value:

const numbers = [4, 8, 15, 16, 23, 42];

if (numbers.indexOf(42) !== -1) {
  // ...
}

The Array.prototype.includes method makes this check easier to read and more semantically meaningful to human readers:

const numbers = [4, 8, 15, 16, 23, 42];

if (numbers.includes(42)) {
  // ...
}

Notice how the if-condition almost reads like a regular English sentence. There's no more fiddling around with indices just to determine array membership.

Looking for NaN

However, there's one edge case in which indexOf and includes behave differently, and that is NaN. Because the strict comparison NaN === NaN returns false, the indexOf method will return -1 when searching for NaN in an array:

assert([NaN].indexOf(NaN) === -1);

Most of the time, this is likely not what you intended. The includes method fixes this behavior and returns true:

assert([NaN].includes(NaN) === true);

As you would expect, the signed zero values +0 and -0 are treated the same as well:

assert([+0].includes(-0) === true);
assert([-0].includes(+0) === true);

Providing a Start Index

The indexOf method accepts an optional second parameter named fromIndex that specifies at which index in the array to start the search:

assert([100, 200, 300].indexOf(100, 0) === 0);
assert([100, 200, 300].indexOf(100, 1) === -1);

For consistency, the includes method accepts this parameter as well:

assert([100, 200, 300].includes(100, 0) === true);
assert([100, 200, 300].includes(100, 1) === false);

A Polyfill for Array.prototype.includes

There's also a spec-compliant polyfill available on MDN that allows you to use Array.prototype.includes today without worrying about browser compatibility:

// https://tc39.github.io/ecma262/#sec-array.prototype.includes
if (!Array.prototype.includes) {
  Object.defineProperty(Array.prototype, 'includes', {
    value: function(searchElement, fromIndex) {

      if (this == null) {
        throw new TypeError('"this" is null or not defined');
      }

      // 1. Let O be ? ToObject(this value).
      var o = Object(this);

      // 2. Let len be ? ToLength(? Get(O, "length")).
      var len = o.length >>> 0;

      // 3. If len is 0, return false.
      if (len === 0) {
        return false;
      }

      // 4. Let n be ? ToInteger(fromIndex).
      //    (If fromIndex is undefined, this step produces the value 0.)
      var n = fromIndex | 0;

      // 5. If n ≥ 0, then
      //  a. Let k be n.
      // 6. Else n < 0,
      //  a. Let k be len + n.
      //  b. If k < 0, let k be 0.
      var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);

      function sameValueZero(x, y) {
        return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));
      }

      // 7. Repeat, while k < len
      while (k < len) {
        // a. Let elementK be the result of ? Get(O, ! ToString(k)).
        // b. If SameValueZero(searchElement, elementK) is true, return true.
        if (sameValueZero(o[k], searchElement)) {
          return true;
        }
        // c. Increase k by 1.
        k++;
      }

      // 8. Return false
      return false;
    }
  });
}

Further Reading

For more details, check out the original feature proposal by Domenic Denicola and Rick Waldron, the current spec draft, or the documentation on MDN.