Клавиша / esc

.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.

На практике

Скопировано

Сергей Минаков советует

Скопировано

🛠 indexOf или findIndex

Скопировано

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

        
          
          const numbers = [1, 7, 4, 6, 2, 8, 3]console.log(numbers.indexOf(2))// 4 (значение 2 хранится по индексу 4)numbers.findIndex((element) => element === 2)// 4
          const numbers = [1, 7, 4, 6, 2, 8, 3]

console.log(numbers.indexOf(2))
// 4 (значение 2 хранится по индексу 4)

numbers.findIndex((element) => element === 2)
// 4

        
        
          
        
      

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

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

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

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

console.log(
  friends.findIndex(
    (element) => element.name === 'Артём'
  )
)
// 2

        
        
          
        
      

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

        
          
          // ссылка на объект 1let tomato = { color: 'red' }// ссылка на объект 2let strawberry = { color: 'red' }
          // ссылка на объект 1
let tomato = { color: 'red' }

// ссылка на объект 2
let strawberry = { color: 'red' }

        
        
          
        
      

Сравнение этих двух объектов вернёт false несмотря на то, что значения ключей объектов одинаковы. Это происходит, потому что сравниваются ссылки на объекты:

        
          
          console.log(tomato === strawberry);// falseconsole.log(tomato === tomato)// true
          console.log(tomato === strawberry);
// false

console.log(tomato === tomato)
// true