Функция map для объектов в JavaScript (аналог Array.prototype.map)
Решение: кастомная функция mapObject
Да, вы правы — у объектов нет встроенного метода map. Но мы можем легко создать свою функцию, которая будет работать похожим образом. Идея в том, чтобы пройти по ключам объекта и применить колбэк к каждому значению, а затем собрать результат в новый объект.
Вот базовая реализация:
function mapObject(obj, callback) {
const result = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = callback(obj[key], key, obj);
}
}
return result;
}
Использование с вашим примером:
const users = {
alice: { age: 25, city: 'Moscow' },
bob: { age: 30, city: 'SPb' },
charlie: { age: 35, city: 'Kazan' }
};
const updatedUsers = mapObject(users, user => ({
...user,
isAdult: user.age >= 18
}));
console.log(updatedUsers);
// {
// alice: { age: 25, city: 'Moscow', isAdult: true },
// bob: { age: 30, city: 'SPb', isAdult: true },
// charlie: { age: 35, city: 'Kazan', isAdult: true }
// }
Почему это работает?
- for...in — перебирает все перечисляемые ключи объекта (включая унаследованные, поэтому мы проверяем
hasOwnProperty). - callback получает три аргумента: текущее значение, ключ и исходный объект — точно как в
Array.prototype.map. - Новый объект создаётся с теми же ключами, но с преобразованными значениями.
Современный вариант с Object.entries()
Если вы используете ES2017+, можно сделать короче и без проверки hasOwnProperty:
function mapObject(obj, callback) {
return Object.fromEntries(
Object.entries(obj).map(([key, value]) => [key, callback(value, key, obj)])
);
}
Этот подход:
Object.entries(obj)— возвращает массив пар[key, value]..map()— применяет колбэк к каждой паре.Object.fromEntries()— собирает массив пар обратно в объект.
Важные замечания
- Порядок ключей — в современных движках строковые ключи сохраняют порядок вставки, но для числовых ключей порядок может отличаться.
- Не мутируйте исходный объект — всегда возвращайте новый объект, это функциональный подход.
- Производительность — для больших объектов цикл
for...inможет быть быстрее, чемObject.entries+map, но разница обычно незаметна.
Альтернатива: библиотека Lodash
Если вы используете lodash, там есть готовая функция _.mapValues:
const updatedUsers = _.mapValues(users, user => ({
...user,
isAdult: user.age >= 18
}));
Она делает ровно то же самое, что мы написали выше. Но для образовательных целей полезно понимать, как это работает «под капотом».
<<Другой подход: использование reduce
Можно также использовать Object.keys() в комбинации с reduce — это более функциональный стиль, который часто встречается в коде:
function mapObject(obj, callback) {
return Object.keys(obj).reduce((acc, key) => {
acc[key] = callback(obj[key], key, obj);
return acc;
}, {});
}
// Пример:
const users = {
alice: { age: 25 },
bob: { age: 30 }
};
const withAdults = mapObject(users, u => ({...u, adult: u.age >= 18}));
console.log(withAdults);
// { alice: { age: 25, adult: true }, bob: { age: 30, adult: true } }
Этот вариант:
- Не требует проверки
hasOwnProperty, так какObject.keys()возвращает только собственные ключи. - Чисто функциональный — нет побочных эффектов.
- Легко читается, если вы знакомы с
reduce.
Когда какой вариант выбрать?
- for...in — если нужна максимальная производительность и совместимость со старыми браузерами.
- Object.entries + fromEntries — если пишете современный код и цените лаконичность.
- reduce — если привыкли к функциональному стилю и используете
reduceв других местах.
Все три подхода работают одинаково хорошо. Выбирайте тот, который вам понятнее и лучше вписывается в стиль вашего проекта.