Кратко
СкопированоМетод массива .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
.
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") })
Результат будет ['
.
Интерактивный пример:
Как пишется
СкопированоАналогично методу .for
, методу .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
.
.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
.
На практике
Скопированосоветует Скопировано
🛠 Так как 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'
.