Объяснение методов массива JavaScript на примере реальных сценариев
Вы когда-нибудь заглядывали в документацию по методам массивов JavaScript и задавались вопросом, как они работают в реальной жизни? Поверьте, методы массивов существуют не только для того, чтобы ломать технические интервью, они ваши ежедневные друзья в разработке в реальном мире.
Сегодня мы покажем вам, когда и как использовать эти методы массивов в реальных проектах. К тому времени, как вы закончите читать, вы увидите, что методы массивов придают вашему коду ясность и читаемость. Не говоря уже о том, что они помогают поддерживать его в рабочем состоянии и удобство в обслуживании.
map() и filter()
Для начала давайте рассмотрим несколько методов массивов, которые вы, скорее всего, будете использовать каждый день — map()
и filter()
.
Создание калькулятора цены продукта с помощью map()
Итак, вы создаете сайт электронной коммерции и у вас есть список товаров, на которые нужно предоставить скидку 20%.
Вот как могут выглядеть данные о вашем продукте:
const products = [
{ name: "Gaming Mouse", price: 59.99 },
{ name: "Mechanical Keyboard", price: 129.99 },
{ name: "4K Monitor", price: 349.99 }
];
Вместо написания запутанного цикла for
, map()
делает это очень чисто:
const discountedPrices = products.map(product => ({
...product,
price: (product.price * 0.8).toFixed(2)
}));
Каждая цена сейчас снижена, и мы сохранили всю нашу оригинальную информацию о продукте. Чисто и просто.
Создание функции интеллектуального поиска с помощью filter()
Теперь давайте создадим что-то покруче — умный поиск, который действительно работает в нескольких полях.
Предположим, у нас есть следующие данные пользователя:
const users = [
{ name: "Sarah Smith", email: "sarah@gmail.com", role: "developer" },
{ name: "John Doe", email: "john@company.com", role: "designer" },
{ name: "Mike Wilson", email: "mike@gmail.com", role: "developer" }
];
Вот как можно легко выполнить поиск с помощью filter()
:
const searchUsers = (query) => {
return users.filter(user =>
user.name.toLowerCase().includes(query.toLowerCase()) ||
user.email.toLowerCase().includes(query.toLowerCase()) ||
user.role.toLowerCase().includes(query.toLowerCase())
);
};
Правильно, вы можете искать по именам, email и ролям. Попробуйте searchUsers("dev")
, и он будет фильтровать только разработчиков.
И если вы думаете, что это круто, подождите, пока мы не доберемся до reduce()
в следующем разделе.
reduce() — больше, чем просто суммы
Большинство разработчиков в основном используют reduce()
только для сложения чисел. Но дело в том, что он способен на гораздо большее.
Расчет общей суммы корзины покупок
Реальный сценарий — это расчет общей стоимости товаров в корзине с учетом скидок и налогов. Посмотрите на это:
const cartItems = [
{ name: "Nike Air Max", price: 129.99, quantity: 2, discount: 20 },
{ name: "Adidas Hoodie", price: 89.99, quantity: 1, discount: 0 },
{ name: "Running Socks", price: 12.99, quantity: 3, discount: 10 }
];
const cartTotal = cartItems.reduce((total, item) => {
const itemTotal = item.price * item.quantity;
const discount = (itemTotal * item.discount) / 100;
return total + (itemTotal - discount);
}, 0);
Здорово, да? Вам нужно реализовать только одну функцию для количества, скидок и общего расчета.
Инструмент статистики документов
А как насчет обработки текстового документа? Считаем все слова, символы и предложения:
const documentStats = paragraphs.reduce((stats, paragraph) => {
return {
words: stats.words + paragraph.split(' ').length,
characters: stats.characters + paragraph.length,
sentences: stats.sentences + paragraph.split(/[.!?]+/).length - 1,
paragraphs: stats.paragraphs + 1
};
}, { words: 0, characters: 0, sentences: 0, paragraphs: 0 });
Итак, разве вы не видите, как красиво reduce()
обрабатывает несколько вещей одновременно? Это намного лучше, чем использование отдельных циклов.
Если обратный вызов reduce()
становится слишком большим, всегда можно использовать небольшие функции.
find() и some()
Давайте рассмотрим два метода, которые значительно упростят ваши системы аутентификации и модерации.
Создание системы аутентификации пользователей
Вы когда-нибудь создавали систему входа? Вот как find()
делает поиск пользователя предельно простым:
const users = [
{ id: 1, email: "alex@tech.com", password: "hashed_password_1", attempts: 0 },
{ id: 2, email: "sam@tech.com", password: "hashed_password_2", attempts: 1 }
];
const authenticateUser = (email, password) => {
const user = users.find(u => u.email === email);
if (!user) return { status: "error", message: "User not found" };
if (user.attempts >= 3) return { status: "error", message: "Account locked" };
return validatePassword(user, password);
};
Больше никаких громоздких циклов или сложных операторов if
. find()
возвращает именно то, что вам нужно.
Создание инструмента модерации контента
Вот где some()
блистает — проверка контента на наличие запрещенных слов или шаблонов:
const bannedWords = ["spam", "scam", "inappropriate"];
const moderateContent = (content) => {
const containsBannedWords = bannedWords.some(word =>
content.toLowerCase().includes(word)
);
const hasSpamPatterns = content.includes("!!!") || content === content.toUpperCase();
return {
isSpam: containsBannedWords || hasSpamPatterns,
reason: containsBannedWords ? "Banned words detected" : "Spam patterns found"
};
};
Посмотрите, как some()
помогает нам проверять несколько условий одновременно. Чисто, читабельно и удобно для обслуживания.
some()
прекращает проверку, как только находит совпадение. Идеально для производительности при работе с большими наборами данных.
flat() и flatMap()
Сглаживатель массива
Вы когда-нибудь пробовали сделать вложенные массивы плоскими? flat()
— ваш лучший друг. Он сглаживает эти вложенные массивы до одного уровня:
const fileSystem = [
"document.txt",
["images", ["vacation.jpg", "wedding.png"]],
["docs", ["resume.pdf", ["certificates", "cert1.pdf"]]]
];
// flat() with a depth of 2 levels
const flatFiles = fileSystem.flat(2);
// Result: ["document.txt", "images", "vacation.jpg", "wedding.png", "docs", "resume.pdf", "certificates", "cert1.pdf"]
Вы даже можете указать глубину выравнивания с помощью параметра глубины. Если глубина не указана, то по умолчанию она равна 1.
flatMap() — система комментариев с множественными ответами
Думайте о flatMap()
как о комбинации flat()
и map()
на вложенном массиве. Он отображает ваш массив и выравнивает результат — все за один раз!
Вот настоящая система комментариев, в которой на каждый комментарий можно дать несколько ответов:
const comments = [
{ id: 1, text: "Great post!", replies: ["Thanks!", "Agreed!"] },
{ id: 2, text: "Question?", replies: ["Let me help", "I know this"] }
];
// Using map() and flat() separately
const allMessages = comments.map(comment => [comment.text, ...comment.replies]).flat();
// Using flatMap() - cleaner and more efficient
const allMessages = comments.flatMap(comment => [comment.text, ...comment.replies]);
// Result: ["Great post!", "Thanks!", "Agreed!", "Question?", "Let me help", "I know this"]
flatMap()
идеально подходит, когда вам нужно преобразовать элементы и обрабатывать вложенные результаты. Это как получить два метода по цене одного!
Вот еще один практический пример — извлечение хэштегов из постов в социальных сетях:
const posts = [
{ text: "Love this! #javascript #webdev" },
{ text: "No hashtags here!" },
{ text: "#react is awesome #frontend" }
];
const hashtags = posts.flatMap(post => {
const matches = post.text.match(/#\w+/g);
return matches || []; // Return empty array if no matches
});
// Result: ["#javascript", "#webdev", "#react", "#frontend"]
Видите, как flatMap()
обрабатывает как преобразование, так и выравнивание потенциально пустых результатов? Довольно ловко!
every() и includes()
Создание системы проверки форм
Давайте попробуем создать то, что мы используем ежедневно — надежный валидатор форм. Вот как every()
делает его чистым:
const formRules = {
password: [
value => value.length >= 8,
value => /[A-Z]/.test(value),
value => /[0-9]/.test(value),
value => /[!@#$%^&*]/.test(value)
]
};
const validatePassword = (password) => {
const passesAllRules = formRules.password.every(rule => rule(password));
return {
isValid: passesAllRules,
message: passesAllRules ? 'Password is strong!' : 'Password too weak'
};
};
every()
проверяет, ВСЕ ли правила пройдены. Вы можете видеть, что это идеально подходит для проверки, когда вам нужно, чтобы все было верно.
Создание средства проверки разрешений
Вот как includes()
значительно упрощает проверку разрешений:
const userRoles = {
admin: ['create', 'read', 'update', 'delete', 'manage_users'],
editor: ['create', 'read', 'update'],
viewer: ['read']
};
const checkPermission = (userRole, action) => {
if (!userRoles[userRole]) return false;
return userRoles[userRole].includes(action);
};
// Quick usage
const canEdit = checkPermission('editor', 'update'); // true
const canDelete = checkPermission('editor', 'delete'); // false
includes()
делает наш код читаемым как обычный английский. Намного лучше, чем сложные операторы if
или циклы.
Упорядочивание данных sort()
Вам когда-нибудь требовалось отсортировать данные за пределами простого алфавитного порядка? sort()
— гораздо более мощный метод, чем думают большинство разработчиков.
Разработка пользовательского сортировщика таблиц
Вот реальный сортировщик таблиц, который обрабатывает различные типы данных:
const tableData = [
{ name: "iPhone 13", price: 799, rating: 4.5, stock: 120 },
{ name: "AirPods Pro", price: 249, rating: 4.8, stock: 45 },
{ name: "MacBook Air", price: 999, rating: 4.7, stock: 80 }
];
const sortTable = (data, column, direction = 'asc') => {
return data.sort((a, b) => {
const modifier = direction === 'asc' ? 1 : -1;
if (typeof a[column] === 'string') {
return a[column].localeCompare(b[column]) * modifier;
}
return (a[column] - b[column]) * modifier;
});
};
// Usage
const sortByPrice = sortTable(tableData, 'price', 'desc');
Больше никаких отдельных функций для разных столбцов. Всего один сортировщик обрабатывает все!
Создание системы рейтинга
Ознакомьтесь с этим сортировщиком таблиц лидеров, который учитывает дополнительные результаты:
const players = [
{ name: "Alex", score: 105, wins: 10, playtime: 150 },
{ name: "Sarah", score: 105, wins: 12, playtime: 140 },
{ name: "Mike", score: 98, wins: 8, playtime: 160 }
];
const leaderboard = players.sort((a, b) => {
if (a.score !== b.score) return b.score - a.score;
if (a.wins !== b.wins) return b.wins - a.wins;
return a.playtime - b.playtime;
});
Посмотрите, как мы обрабатываем несколько критериев сортировки? Сначала набираете очки, затем побеждаете, затем наименьшее игровое время разрешает ничью.
Всегда создавайте копию массива перед сортировкой, если вам необходимо сохранить исходный порядок.
Когда использовать какой метод
Вот мое практическое руководство, основанное на том, что вы пытаетесь сделать:
// Need new array with changes? → map()
const prices = items.map(item => item.price * 1.2);
// Need to filter stuff out? → filter()
const inStock = products.filter(product => product.stock > 0);
// Need a single value from calculations? → reduce()
const total = cart.reduce((sum, item) => sum + item.price, 0);
// Need first match? → find()
const user = users.find(u => u.id === userId);
Так что перестаньте беспокоиться о forEach
и циклах for
. Сосредоточьтесь на них.
Делать и не делать то, что действительно имеет значение
И последнее, прежде чем вы уйдете. Всегда ищите способ сделать что-то проще и лучше. Например:
Вместо этого:
const result = items
.filter(item => item.price > 20)
.map(item => item.name)
.filter(name => name.length > 5);
Всегда делайте это:
// GOOD: Combine operations in one pass
const result = items.reduce((acc, item) => {
if (item.price > 20 && item.name.length > 5) {
acc.push(item.name);
}
return acc;
}, []);
Вот и все! Теперь у вас есть практические, реальные знания методов массивов JavaScript. Используйте их с умом!
Читабельность кода лучше микрооптимизаций. Выберите метод, который сделает ваш код наиболее понятным.