JavaScript: includes vs indexOf

Начиная с ECMAScript 2016 в JavaScript появился новый метод includes для работы с массивами. По своей сути он очень сильно напоминает indexOf. В этой статье я хочу рассмотреть подробнее для чего был введен этод метод и в чем его отличие от indexOf.

image

Массивы
Итак, метод Array.prototype.includes определяет содержится ли в массиве искомое значение и возвращает true или false. Таким образом, в отличие от indexOf, который возвращает целое число, includes возвращает значение типа boolean. Это нововведение поможет разработчикам писать более чистый и понятный код.

Например, вот стандартный пример проверки того, содержится ли элемент в массиве, с помощью indexOf:

var numbers = [3, 5, 8, 11, 23, 7];

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

Используя includes, то же самое можно написать так:

var numbers = [3, 5, 8, 11, 23, 7];

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

Также при внедрении этого метода были учтены некоторые неочевидные особенности, замеченные при работе с indexOf. В отношении значений NaN поведение этого метода отличается.

Рассмотрим на примере:

var numbers = [3, 5, 8, 11, 23, 7, NaN];
if (numbers.indexOf(NaN) !== -1) {
    // Этот код не выполнится
}

if (numbers.includes(NaN)) {
    // Этот код выполнится
}

Таким образом, indexOf (NaN) всегда возвращает -1, независимо от того содержится ли это значение в массиве, а includes (NaN) возвращает true или false в зависимости от того есть этот элемен в массиве или нет.

Производительность

Оценка производительности javascript методов не такая уж очевидная вешь, так как по сути в разных браузерах одна и та же функция может быть реализована по-разному в зависимости от языка, на котором написан сам браузер. К тому же очень много зависит от компьютера, на котором делается эта оценка. Но, тем не менее, я попытался сделать небольшой анализ.

Я создал массив из 10000 целых положительных чисел и использовал для анализа сайт jsbench.github.io
В обоих случаях, для чистоты эксперимента, был использован один и тот же массив. Оценка производилась в браузерах Chrome 53 и Firefox 48.

Chrome
includes indexOf
элемент есть
в середине массива
8,361 ops/sec ±0.38% 31,296 ops/sec ±0.65%
элемент есть
в начале массива
22,043,904 ops/sec ±1.89% 136,512,737 ops/sec ±2.06%
искомого эелемента
нет в массиве
4,018 ops/sec ±0.71% 95,221 ops/sec ±0.53%
Firefox
includes indexOf
элемент есть
в середине массива
84,880 ops/sec ±0.59% 86,612 ops/sec ±1.35%
элемент есть
в начале массива
34,087,623 ops/sec ±0.99% 33,196,839 ops/sec ±0.84%
искомого эелемента
нет в массиве
25,253 ops/sec ±2.75% 14,994 ops/sec ±1.16%

Получается, что в Chrome indexOf всегда работает быстрее, а в Firefox ощутимой разницы практически нет (кроме случая, когда в массиве нет искомого элемента). И поведение нового метода в Firefox кажется более логичным, так как в общем-то indexOf и includes по логике должны иметь одну и ту же вычислительную сложность.

Строки
Аналогичный метод был добавлен и для работы со строками начиная с ECMAScript 2015. Ранее в Firefox в версиях с 18 по 39 этот метод существовал под именем contains, однако из-за проблем совместимости он был переименован в includes ().

В заключение следует отметить, что данный метод поддерживается пока что не всеми браузерами.

Браузер Массив Строки
Chrome 47 41
Firefox 43 40
IE нет нет
Opera 34 нет
Safari 9 9

Комментарии (5)

  • 24 октября 2016 в 08:28

    –1

    Вариация по теме:


    var numbers = [3, 5, 8, 11, 23, 7];
    
    if ( ~numbers.indexOf(1) ) {
        // ...
    }
  • 24 октября 2016 в 08:45

    0

    > так как в общем-то indexOf и includes по логике должны иметь одну и ту же вычислительную сложность.

    Сложность у них разная будет, как ни крути. Вы же сами выше писали, что indexOf не правильно работает с NaN.

    Для исправления этого огреха с NaN необходимо проверять каждый элемент массива на isNaN, при этом нужно будет проверить еще и тип элемента, т.к. isNaN ('a') == true.

    В то время когда Array.indexOf будет сравнивать по ссылке, а в некоторых случаях еще и по значению.

    • 24 октября 2016 в 09:19

      0

      Угу. И судя по результатам, такая проверка у Firefox была (есть) и у indexOf.
    • 24 октября 2016 в 09:38

      0

      Согласен с этим. Но меня удивило, что иногда результаты тестов отличаются на порядок.
      • 24 октября 2016 в 09:40 (комментарий был изменён)

        0

        Не удивляйтесь. В погоне за фичами, сейчас все разработчики движков сначала их делают, иногда даже прямо на js, и только потом оптимизируют.

© Habrahabr.ru