Array.prototype.includes против Array.prototype.indexOf


113

Помимо улучшения читаемости, есть ли преимущество includesнад indexOf? Мне они кажутся идентичными.

В чем разница между этим

var x = [1,2,3].indexOf(1) > -1; //true

И это?

var y = [1,2,3].includes(1); //true

12
includesимеет гораздо худшую поддержку браузера.
Квентин

4
Обратите внимание, что includesэто не часть ES6 / ES2015. Это предложение для следующей версии ECMAScript, которое будет добавлено в этом году.
Феликс Клинг,

4
просто хотел также упомянуть, что includesвообще НЕ поддерживается в IE
ZvKa

Ответы:


139

tl; dr: NaN обрабатывается иначе:

  • [NaN].indexOf(NaN) > -1 является false
  • [NaN].includes(NaN) является true

Из предложения :

Мотивация

При использовании массивов ECMAScript обычно требуется определить, включает ли массив элемент. Преобладающий образец для этого -

if (arr.indexOf(el) !== -1) {
    ...
}

с различными другими возможностями, например arr.indexOf(el) >= 0, или даже ~arr.indexOf(el).

Эти шаблоны вызывают две проблемы:

  • Они не могут «сказать, что вы имеете в виду»: вместо того, чтобы спрашивать, включает ли массив элемент, вы спрашиваете, каков индекс первого вхождения этого элемента в массиве, а затем сравниваете его или перебираете, чтобы определить ответ на ваш актуальный вопрос.
  • Они терпят неудачу NaN, поскольку indexOfиспользуют строгое сравнение равенства и таким образом [NaN].indexOf(NaN) === -1.

Предложенное решение

Мы предлагаем добавить Array.prototype.includesметод, позволяющий переписать вышеприведенные шаблоны как

if (arr.includes(el)) {
    ...
}

Он имеет почти ту же семантику, что и выше, за исключением того, что он использует алгоритм сравнения SameValueZero вместо строгого сравнения равенства, что делает его [NaN].includes(NaN)истинным.

Таким образом, это предложение решает обе проблемы, обнаруженные в существующем коде.

Мы дополнительно добавляем fromIndexпараметр, аналогичный Array.prototype.indexOfи String.prototype.includes, для единообразия.


Дальнейшая информация:


1
Только половина правды. Кроме того, различные: Недостающие элементы рассматриваются как undefinedпуть .includes()и не рассматриваются .indexOf().
Роберт Симер

11

Если вас интересует производительность, на данный момент indexOf работает быстрее, но этот тест JSperf, как правило, показывает, что чем больше времени проходит, тем includes()быстрее будет больше indexOf(я думаю, он будет оптимизирован дальше).

ИМХО, я тоже предпочитаю писать, if (arr.includes(el)) {}так как он понятнее и удобнее, чемif (arr.indexOf(el) !== -1) {}


1
Похоже, разница в производительности не так очевидна. Мой мобильный Firefox показывает, что indexOf на самом деле быстрее. Некоторые версии Chrome действуют одинаково ... Но в сегодняшних реализациях разница в любом случае кажется незначительной.
Nux

8

.indexOf()и .includes()методы могут использоваться для поиска элемента в массиве или для поиска символа / подстроки в заданной строке.

Использование в массиве

( Ссылка на спецификацию ECMAScript)

  1. indexOfиспользует строгое сравнение равенства, тогда как includesиспользует алгоритм SameValueZero . По этой причине возникают следующие два момента различий.

  2. Как указал Феликс Клинг , в случае NaN.

let arr = [NaN];

arr.indexOf(NaN); // returns -1; meaning NaN is not present
arr.includes(NaN); // returns true
  1. Поведение также отличается в случае undefined.
let arr = [ , , ];

arr.indexOf(undefined); // returns -1; meaning undefined is not present
arr.includes(undefined); // returns true

Использование в строке

( Ссылка на спецификацию ECMAScript)

  1. Если вы передадите RegExp в indexOf, он будет рассматривать RegExp как строку и вернет индекс строки, если он найден. Однако, если вы передадите RegExp в includes, он выдаст исключение.
let str = "javascript";

str.indexOf(/\w/); // returns -1 even though the elements match the regex because /\w/ is treated as string
str.includes(/\w/); // throws TypeError: First argument to String.prototype.includes must not be a regular expression

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

Как указал 538ROMEO , это includesможет быть немного (очень крошечное) немного медленнее (поскольку ему нужно проверять регулярное выражение в качестве первого аргумента), чем, indexOfно на самом деле это не имеет большого значения и незначительно.

История

String.prototype.includes()был представлен в ECMAScript 2015, тогда как Array.prototype.includes()был представлен в ECMAScript 2016. Что касается поддержки браузеров, используйте их с умом.

String.prototype.indexOf()и Array.prototype.indexOf()присутствуют в версии ECMAScript для ES5 и, следовательно, поддерживаются всеми браузерами.


indexOfдает trueпосле явной установки undefinedв массив: let arr=[undefined];or let arr=[];arr[0]=undefined;Nowarr.indexOf(undefined) === 0
Джей Дадхания

Вы единственный, кто указывает разницу undefined: Причина в том, что .includesпропущенные элементы обрабатываются как undefined, а .indexOf()игнорируются. Вы также можете «создать» недостающие элементы с помощью arr[number beyond length] = whatever.
Роберт Симер,

Никто не просил струны, но ваши замечания говорят о том, что .includes()ест только струны. На самом деле оба метода как можно лучше приводят к строке что угодно. Regex специально исключен в качестве аргумента , .includes()чтобы позволить для будущих дополнений к стандарту в соответствии с текущим проектом.
Роберт Симер

4

По идее, вы должны использовать indexOf, когда хотите использовать позицию indexOf, которая просто дает вам извлекать значение или работать с массивом, то есть с помощью среза, сдвига или разделения после того, как вы получили позицию элемента. С другой стороны, Use Array.includes только для того, чтобы знать, находится ли значение внутри массива, а не позиция, потому что вам это не важно.


0

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

indexOfвозвращает число ( -1если элемент отсутствует в массиве, или позицию массива, если элемент присутствует).

includes()возвращает логическое значение ( trueили false).


Привет, Крути, на этот вопрос уже дан ответ, и на него есть принятый ответ. Кроме того, вы можете увидеть, что ваш ответ содержит только информацию, уже упомянутую в других ответах. Вопросу, в конце концов, уже 4 года. Пожалуйста, дайте рекомендации по новым или остающимся без ответа вопросам. Спасибо
leonardfactory
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.