[].filter

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

Кратко

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

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

Пример

Секция статьи "Пример"
        
          
          const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]const evenOnly = nums.filter(function (n) {  const remainder = n % 2  return remainder === 0})
          const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

const evenOnly = nums.filter(function (n) {
  const remainder = n % 2

  return remainder === 0
})

        
        
          
        
      

Результат будет [2, 4, 6, 8, 10].

        
          
          const languages = ["Java", "TypeScript", "C#", "JavaScript", "Julia"]const jLanguages = languages.filter(function (language) {  return language.startsWith("J")})
          const languages = ["Java", "TypeScript", "C#", "JavaScript", "Julia"]

const jLanguages = languages.filter(function (language) {
  return language.startsWith("J")
})

        
        
          
        
      

Результат будет ['Java', 'JavaScript', 'Julia'].

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

Открыть демо в новой вкладке

Как пишется

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

Аналогично методу forEach, методу filter необходимо передать аргументом функцию. Главное отличие — функция должна возвращать boolean, т. е. результатом должен быть true или false. Такие функции называют предикатами.

Это предикат, т. к. функция возвращает boolean-результат сравнения:

        
          
          function isPositive(num) {  return num > 0}
          function isPositive(num) {
  return num > 0
}

        
        
          
        
      

Это предикат, т. к. метод includes у строки возвращает boolean:

        
          
          function hasChar(str, char) {  return str.includes(char)}
          function hasChar(str, char) {
  return str.includes(char)
}

        
        
          
        
      

А вот это не предикат, т. к. функция возвращает число, даже несмотря на то, что любое число в JavaScript (кроме 0) может быть приведено к true:

        
          
          function sum(a, b) {  return a + b}
          function sum(a, b) {
  return a + b
}

        
        
          
        
      

От результата выполнения функции зависит, попадёт ли элемент в итоговый массив:

  • true — элемент попадёт в итоговый массив.
  • false — не попадёт в итоговый массив.
        
          
          function predicate(num) {  if (num >= 5) {    return true  }  return false}const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]// передаём предикатnums.filter(predicate) // [5, 6, 7, 8, 9, 10]// Либо делаем короче и просто возвращаем результат сравненияnums.filter((num) => num >= 5) // [5, 6, 7, 8, 9, 10]
          function predicate(num) {
  if (num >= 5) {
    return true
  }

  return false
}

const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

// передаём предикат
nums.filter(predicate) // [5, 6, 7, 8, 9, 10]

// Либо делаем короче и просто возвращаем результат сравнения
nums.filter((num) => num >= 5) // [5, 6, 7, 8, 9, 10]

        
        
          
        
      

Функция, которую мы передаём в метод filter, принимает три параметра:

  • item — элемент массива в текущей итерации;
  • index — индекс текущего элемента;
  • arr — сам массив, который мы перебираем.
        
          
          const languages = ["Java", "TypeScript", "C#", "JavaScript", "Julia"]languages.filter(function (item, index, arr) {  console.log("Текущий элемент " + item)  console.log("Индекс " + index)  console.log("Массив " + arr)  return index >= 3})
          const languages = ["Java", "TypeScript", "C#", "JavaScript", "Julia"]

languages.filter(function (item, index, arr) {
  console.log("Текущий элемент " + item)
  console.log("Индекс " + index)
  console.log("Массив " + arr)

  return index >= 3
})

        
        
          
        
      

💡 В новом массиве отфильтрованные элементы будут находиться в том же порядке, в котором они были в исходном массиве.

💡 filter возвращает новый массив, при этом исходный массив никак не изменится.

💡 Из-за того, что JavaScript имеет динамическую типизацию, то нам ничего не мешает возвращать какое угодно значение из функции. В этом случае JavaScript сам определит его истинность. Стоит помнить, что значения 0, undefined, null и пустая строка '' считаются ложными и равны false.

Truthy и falsy: Преобразование типов.

        
          
          const goods = [  {    name: "AirPods",    description: "Классные беспроводные наушники",  },  {    name: "MacBook Pro",    description: "Ноутбук на все случаи жизни",  },  {    name: "iPhone",    description: "",  },  {    name: "Дошик",  },]// Просто возвращаем значения описанияconst withDescription = goods.filter(function (item) {  return item.description})
          const goods = [
  {
    name: "AirPods",
    description: "Классные беспроводные наушники",
  },
  {
    name: "MacBook Pro",
    description: "Ноутбук на все случаи жизни",
  },
  {
    name: "iPhone",
    description: "",
  },
  {
    name: "Дошик",
  },
]

// Просто возвращаем значения описания
const withDescription = goods.filter(function (item) {
  return item.description
})

        
        
          
        
      

В результате получим массив с AirPods и MacBook Pro.

Для хорошей читаемости и понимания кода лучше всегда явно возвращать boolean-значение из функции-предиката.

💡 В JavaScript функция, в которой нет явного возвращаемого значения (т. е. нет return) все равно возвращает undefined. Потому, если забыть вернуть результат в функции в методе filter, то в результате получим пустой массив, так как отфильтруются все элементы.

        
          
          const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]const filtered = nums.filter(function (num) {  // Забыли вернуть результат  num >= 5})
          const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

const filtered = nums.filter(function (num) {
  // Забыли вернуть результат
  num >= 5
})

        
        
          
        
      

Получим [], потому что undefined считается как false.

Как это понять

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

Метод filter позволяет получить новый массив с отфильтрованными значениями на основании данных исходного. Несмотря на то, что то же самое можно сделать, используя обычный цикл for или while, метод filter позволяет сделать это проще.

Если решать такую задачу без filter, то выйдет так:

        
          
          const nums = [1, 2, 3, 4, 5, 6]const odds = []for (let i = 0; i < nums.length; i++) {  if (nums[i] % 2 !== 0) {    odds.push(nums[i])  }}console.log(odds)
          const nums = [1, 2, 3, 4, 5, 6]
const odds = []

for (let i = 0; i < nums.length; i++) {
  if (nums[i] % 2 !== 0) {
    odds.push(nums[i])
  }
}

console.log(odds)

        
        
          
        
      

Результат будет [1, 3, 5].

filter позволит сильно сократить код и сделать его понятнее:

        
          
          const nums = [1, 2, 3, 4, 5, 6]const odds = nums.filter(function (num) {  return num % 2 !== 0})console.log(odds)
          const nums = [1, 2, 3, 4, 5, 6]

const odds = nums.filter(function (num) {
  return num % 2 !== 0
})
console.log(odds)

        
        
          
        
      

Результат — [1, 3, 5].

На практике

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

Егор Огарков

Секция статьи "Егор Огарков"

🛠 Так как filter возвращает массив, то у полученного массива мы можем продолжать по цепочке вызывать другие методы массива.

        
          
          const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]const result = nums.filter(num => num >= 5).map(...).reduce(...)
          const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

const result = nums.filter(num => num >= 5).map(...).reduce(...)

        
        
          
        
      

🛠 В filter в качестве функции можно передать конструктор Boolean. Таким образом можно легко и быстро отфильтровать все элементы, которые при приведении к boolean будут равны false.

        
          
          const num = 3const elements = [0, "", "one", "two", num === 3 && "three", null].filter(  Boolean)
          const num = 3

const elements = [0, "", "one", "two", num === 3 && "three", null].filter(
  Boolean
)

        
        
          
        
      

Результат — ['one', 'two', 'three'].