Object.keys + map против for...in: баги с прототипами при нормализации API-данных
-
Нормализация данных из API часто ломается на неожиданных свойствах из прототипов. for…in тянет за собой унаследованные ключи, а Object.keys + map держит только свои. Это спасает от багов в валидации и трансформации.
В реальном проекте API кидает объект с полями userId, name, email. Кажется, что for…in пройдется по ним чисто. Но если где-то в цепочке прототипов висит toString или valueOf - привет, лишние итерации и кривая логика. Object.keys фильтрует их на корню, map добавляет трансформацию без костылей.
Почему for…in - это мина под нормализацией
for…in перебирает все enumerable свойства, включая те, что притащились из прототипа. В API-данных это редко заметно на чистых объектах {}, но стоит унаследовать от Array.prototype или Object.prototype - и код фейлит. Представь: нормализуешь response.data, мапишь id в upperCase, а вместо name ловишь constructor из прототипа.
Проблема вылазит при рефакторе, когда добавляешь полифиллы или расширяешь Object.prototype. hasOwnProperty спасает, но это boilerplate в каждом цикле. Object.keys() возвращает массив только собственных ключей - прототипы отсекаются автоматически. С map() или for…of получаешь чистую итерацию с трансформацией на лету.
- Enumerable свойства из прототипа: for…in их подхватывает, keys() - игнорит.
- Порядок итерации: в keys() - как в объекте, в for…in - не гарантирован.
- Производительность: на больших объектах keys() + map быстрее for…in с проверками.
Свойство for…in Object.keys() + map Собственные ключи Только с hasOwnProperty Автоматически Прототипы Перебирает Игнорирует Трансформация Ручная в цикле Через map() Память Минимальная + массив ключей, но оптимизировано Нормализация API: реальные грабли с примерами
API возвращает { users: [{id:1, name:‘John’}, {id:2}] }. Нормализуешь в {1: {name:‘John’}, 2: {…}}. for…in по users увидит toString, если массив унаследовал прототип. Результат - лишний ключ в нормализованном объекте, валидация слетает.
Object.keys(users).reduce((acc, id) => { acc[id] = normalizeUser(users[id]); return acc; }, {}). Здесь map заменит reduce для brevity, прототипы не лезут. В больших респонсах разница в памяти и скорости критична - for…in с hasOwnProperty тормозит на 100k свойствах.
// Плохо: for...in for(let key in apiData) { if (apiData.hasOwnProperty(key)) { normalized[key.toUpperCase()] = apiData[key]; } } // Хорошо: keys + map const normalized = Object.keys(apiData) .map(key => ({ [key.toUpperCase()]: apiData[key] })) .reduce((acc, pair) => ({...acc, ...pair}), {});- Баг #1: toString в валидации форм - поле ‘toString’ не проходит схему.
- Баг #2: valueOf мешает числовым id при маппинге.
- Баг #3: Расширенный прототип (lodash._) ломает всю цепочку.
Object.entries() как альтернатива map
Entries() дает пары [key, value] сразу - идеально для нормализации без двойного доступа obj[key]. for…in требует ручного obj[key], что на слабых девайсах жрет циклы. map над entries() - функциональный стиль без мутаций.
В API с nested объектами entries() + flatMap рвут for…in по читаемости. Прототипы? Забудь - entries() только свои свойства. Плюс, работает с destructuring: for(const [key, val] of Object.entries(obj)).
Метод Когда юзать Минусы keys() + map Простая трансформация ключей Лишний шаг для значений entries() Ключ-значение пары Больше памяти на массив for…of keys() Иммутабельность Строго JS2015+ - Гибкость: destructuring в map(([, value]) => transform(value)).
- С Map вместо Object: для динамических ключей из API - size() без keys().length.
- Proxy хак: перехват ownKeys() для валидации на лету.
Когда for…in все же прокатит - и зачем его добивать
Редко, но бывает: дебуггинг полного прототипа или legacy код. hasOwnProperty решает 90% багов, но добавляет шум. В нормализации API это антипаттерн - данные чистые, прототипы не нужны.
Переходи на keys()/entries() - рефактор за 5 минут, баги в прошлом. Производительность на больших payload’ах дает +70%. Остальное - итераторы под капотом и Reflect API для edge cases.
Дальше копай Reflect.ownKeys для non-enumerable свойств или WeakMap для кэша нормализованных данных. Прототипы останутся в прошлом, код - чистым.
Здравствуйте! Похоже, вас заинтересовала эта беседа, но у вас ещё нет аккаунта.
Надоело каждый раз пролистывать одни и те же посты? Зарегистрировав аккаунт, вы всегда будете возвращаться на ту же страницу, где были раньше, и сможете выбирать, получать ли уведомления о новых ответах (по электронной почте или в виде push-уведомлений). Вы также сможете сохранять закладки и ставить лайки постам, чтобы выразить свою благодарность другим участникам сообщества.
С вашими комментариями этот пост мог бы стать ещё лучше 💗
Зарегистрироваться Войти© 2024 - 2026 ExLends, Inc. Все права защищены.