.findIndex()

Позволяет узнать индекс первого подходящего под условие элемента

Время чтения: меньше 5 мин

Кратко

Секция статьи "Кратко"

Метод findIndex() возвращает индекс первого найденного в массиве элемента, который подходит под условие переданной функции. Если же ни одного подходящего элемента не найдётся, то метод вернёт -1.

Пример

Секция статьи "Пример"

Напишем код, который позволит найти человека в списке гостей мероприятия. Для этого определим функцию, которая будет получать имя из массива участников и сверять его с константой guestName. Затем передадим эту функцию в метод findIndex():

        
          
          function isWantedGuest(element, index, array) {  const guestName = 'Лиза'  return element === guestName}const partyGuests = [  'Даня',  'Саша',  'Юля',  'Лиза',  'Егор']const meetingGuests = [  'Даня',  'Егор',  'Арсений']console.log(partyGuests.findIndex(isWantedGuest))// 3 (так как partyGuests[3] -> 'Лиза')console.log(meetingGuests.findIndex(isWantedGuest))// -1 (так как совпадений нет)
          function isWantedGuest(element, index, array) {
  const guestName = 'Лиза'

  return element === guestName
}

const partyGuests = [
  'Даня',
  'Саша',
  'Юля',
  'Лиза',
  'Егор'
]

const meetingGuests = [
  'Даня',
  'Егор',
  'Арсений'
]

console.log(partyGuests.findIndex(isWantedGuest))
// 3 (так как partyGuests[3] -> 'Лиза')

console.log(meetingGuests.findIndex(isWantedGuest))
// -1 (так как совпадений нет)

        
        
          
        
      

Интерактивный пример

Секция статьи "Интерактивный пример"
Открыть демо в новой вкладке

Как пишется

Секция статьи "Как пишется"

Метод findIndex() обходит массив и возвращает индекс первого элемента, который подходит под условие функции-предиката. Если ничего не подошло, то он возвращает -1.

Функция, которую мы передаём в метод findIndex(), может принимать три параметра:

  • element — элемент массива в текущей итерации;
  • index — индекс текущего элемента;
  • array — сам массив, который перебираем.

Определим функцию isEven, которая проверяет, является ли число чётным, то есть делится на два без остатка. А затем найдём в массиве индекс первого такого числа через findIndex().

        
          
          // Если число чётное — вернёт true,// если нечётное — falsefunction isEven(element) {  return element % 2 === 0}const onlyOddNumbers = [1, 3, 5, 7, 9]const randomNumbers = [7, 1, 6, 3, 5]console.log(onlyOddNumbers.findIndex(isEven))// -1 (элемент не найден)console.log(randomNumbers.findIndex(isEven))// 2 (так как randomNumbers[2] -> 6)
          // Если число чётное — вернёт true,
// если нечётное — false
function isEven(element) {
  return element % 2 === 0
}

const onlyOddNumbers = [1, 3, 5, 7, 9]
const randomNumbers = [7, 1, 6, 3, 5]

console.log(onlyOddNumbers.findIndex(isEven))
// -1 (элемент не найден)

console.log(randomNumbers.findIndex(isEven))
// 2 (так как randomNumbers[2] -> 6)

        
        
          
        
      

В этом примере функция isEven не использует параметры index и array, поэтому мы не стали их объявлять.

Как понять

Секция статьи "Как понять"

Найти индекс первого подходящего элемента можно и с помощью цикла for, но метод findIndex() позволяет сделать это декларативно. С помощью функции-колбэка мы описываем, какой элемент мы ищем и не описываем как должен происходить поиск. Поиск с помощью цикла for содержал бы гораздо больше деталей.

Давайте сами попробуем реализовать findIndex, чтобы лучше понять, как он работает «под капотом».

        
          
          function findIndex(array, predicate) {  for (let i = 0; i < array.length; i++) {    // Если элемент удовлетворяет условию,    // то возвращаем его индекс    if (predicate(array[i], i, array)) {      return i    }  }  // Если ничего не подошло,  // то возвращаем -1  return -1}function isEven(element) {  return element % 2 === 0}const onlyOddNumbers = [1, 3, 5, 7, 9]const randomNumbers = [7, 1, 6, 3, 5]console.log(findIndex(onlyOddNumbers, isEven))// -1console.log(findIndex(randomNumbers, isEven))// 2
          function findIndex(array, predicate) {
  for (let i = 0; i < array.length; i++) {
    // Если элемент удовлетворяет условию,
    // то возвращаем его индекс
    if (predicate(array[i], i, array)) {
      return i
    }
  }

  // Если ничего не подошло,
  // то возвращаем -1
  return -1
}

function isEven(element) {
  return element % 2 === 0
}

const onlyOddNumbers = [1, 3, 5, 7, 9]
const randomNumbers = [7, 1, 6, 3, 5]

console.log(findIndex(onlyOddNumbers, isEven))
// -1

console.log(findIndex(randomNumbers, isEven))
// 2

        
        
          
        
      

Подсказки

Секция статьи "Подсказки"

💡 Если используете findIndex в условии, то всегда явно проверяйте возвращаемое значение на `-1.

На практике

Секция статьи "На практике"

cergmin

Секция статьи "cergmin"

🛠 indexOf или findIndex

Секция статьи "🛠 indexOf или findIndex"

Помимо findIndex, у массивов есть ещё и метод indexOf. Он работает схожим образом: возвращает индекс первого подходящего элемента или -1, но, в отличии от findIndex, принимает как аргумент не функцию-предикат, а искомое значение.

        
          
          const numbers = [1, 7, 4, 6, 2, 8, 3];// Вернёт: 4// numbers[4] -> 2numbers.indexOf(2);// Вернёт: 4// numbers[4] -> 2numbers.findIndex((element) => element === 2);
          const numbers = [1, 7, 4, 6, 2, 8, 3];

// Вернёт: 4
// numbers[4] -> 2
numbers.indexOf(2);

// Вернёт: 4
// numbers[4] -> 2
numbers.findIndex((element) => element === 2);

        
        
          
        
      

Кажется, что метод indexOf проще в использовании, и это действительно так, но из-за своей простоты, он уступает методу findIndex в функциональности.

Например, если мы хотим осуществить поиск по массиву объектов, то indexOf вряд ли сможет нам помочь.

        
          
          const friends = [  { name: "Андрей" },  { name: "Маша" },  { name: "Артём" }];// Вернёт: -1// Элемент не найденfriends.indexOf({ name: "Артём" });// Вернёт: 2// friends[2] -> { name: "Артём" }friends.findIndex(  (element) => element.name === "Артём");
          const friends = [
  { name: "Андрей" },
  { name: "Маша" },
  { name: "Артём" }
];

// Вернёт: -1
// Элемент не найден
friends.indexOf({ name: "Артём" });

// Вернёт: 2
// friends[2] -> { name: "Артём" }
friends.findIndex(
  (element) => element.name === "Артём"
);

        
        
          
        
      

Дело в том, что переменная не хранит в себе содержимое объекта, она содержит только ссылку на него. Следовательно, indexOf сравнивает ссылки, а не сами объекты.

        
          
          // Содержит: [ссылка на объект 1]let tomato = { color: 'red' };// Содержит: [ссылка на объект 2]let strawberry = { color: 'red' };// Вернёт: false// Потому что сравниваются ссылки на разные объекты,// хотя у этих объектов и одинаковое содержаниеconsole.log(tomato === strawberry);// Вернёт: true// Потому что сравниваются одинаковые ссылки,// то есть они указывают на один и тот же объектconsole.log(tomato === tomato);
          // Содержит: [ссылка на объект 1]
let tomato = { color: 'red' };

// Содержит: [ссылка на объект 2]
let strawberry = { color: 'red' };

// Вернёт: false
// Потому что сравниваются ссылки на разные объекты,
// хотя у этих объектов и одинаковое содержание
console.log(tomato === strawberry);

// Вернёт: true
// Потому что сравниваются одинаковые ссылки,
// то есть они указывают на один и тот же объект
console.log(tomato === tomato);