<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[for...in против Object.keys + for...of: почему прототипы ломают валидацию формы]]></title><description><![CDATA[<p dir="auto">for…in и Object.keys() + for…of кажутся похожими способами пройтись по свойствам объекта. Но первый тащит за собой прототипы, а второй - чисто свои ключи. В валидации форм это выливается в баги: проверяешь поля, а вместо них ловишь toString из прототипа.</p>
<p dir="auto">Разница критична в реальном коде. for…in перебирает все enumerable свойства, включая унаследованные. Object.keys() фильтрует только собственные. Без hasOwnProperty или современного подхода форма валидируется криво, пропуская ошибки или фейля лишнее.</p>
<h2>Как for…in подцепляет прототипы</h2>
<p dir="auto">Цикл for…in идет по всем перечисляемым свойствам объекта, включая те, что висят в цепочке прототипов. Представь типичный случай: валидация формы, где объект полей расширяет какой-то базовый Validator. Прототип несет методы вроде isValid, toString, valueOf - все они enumerable по умолчанию.</p>
<p dir="auto">В цикле ты ожидаешь только name, email, age. А получаешь их плюс прототипный мусор. Без проверки hasOwnProperty(key) код сломается: вместо валидации полей начнет ковырять методы, которые не предназначены для этого. Современные движки вроде V8 перебирают в порядке создания, но порядок - не спасение от лишних свойств.</p>
<p dir="auto">Это классическая грабля для мидлов: пишут валидатор, тестируют на пустом объекте - работает. Добавляют прототип - и привет, утечка логики.</p>
<ul>
<li><strong>Enumerable свойства прототипа участвуют всегда</strong>: toString из Object.prototype попадет в цикл, если не фильтровать.</li>
<li><strong>Порядок не гарантирован</strong>: сначала числовые ключи по возрастанию, потом строковые по созданию - но прототипы мешаются.</li>
<li><strong>Символьные ключи игнорируются</strong>: for…in работает только со строками, Symbols пропускает.</li>
</ul>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Свойство</th>
<th>for…in</th>
<th>Object.keys()</th>
</tr>
</thead>
<tbody>
<tr>
<td>Собственные свойства</td>
<td>Да</td>
<td>Да</td>
</tr>
<tr>
<td>Прототипные свойства</td>
<td><strong>Да</strong></td>
<td>Нет</td>
</tr>
<tr>
<td>Порядок</td>
<td>Сортировка числовых + хронология строк</td>
<td>Хронология создания</td>
</tr>
<tr>
<td>Символы</td>
<td>Игнор</td>
<td>Только строковые</td>
</tr>
</tbody>
</table>
<h2>Object.keys() + for…of: чистый перебор без костылей</h2>
<p dir="auto">Object.keys() возвращает массив только собственных enumerable свойств. Дальше for…of бежит по нему - никаких прототипов, никакой грязи. В валидации это идеал: проверяешь ровно те поля, что добавил сам.</p>
<p dir="auto">Пример: форма с полями userData = {name: ‘’, email: ‘invalid’, age: 150}. Цикл по Object.keys(userData) увидит только эти трое. Никаких toString или hasOwnProperty из прототипа. Производительность? keys() создает массив - да, но для форм это копейки, а предсказуемость бесценна.</p>
<p dir="auto">Сравни с for…in + hasOwnProperty: тот же эффект, но boilerplate. А for…of на entries() дает сразу ключ-значение: for (const [key, value] of Object.entries(obj)). Чисто, современно, без var.</p>
<ul>
<li><strong>Только собственные ключи</strong>: прототипы отсекаются на старте, hasOwnProperty не нужен.</li>
<li><strong>Итерируемость</strong>: for…of работает с массивом, порядок как в объекте.</li>
<li><strong>Entries для пар</strong>: Object.entries() - для ключ-значение без лишних обращений obj[key].</li>
</ul>
<pre><code class="language-javascript">// Плохо: for...in с прототипами
const validatorProto = { isValid() { return true; } };
const formData = Object.create(validatorProto);
formData.name = '';

for (let key in formData) {
  console.log(key); // name, isValid - мусор!
}

// Хорошо: Object.keys + for...of
const cleanKeys = Object.keys(formData); // ['name']
for (const key of cleanKeys) {
  validateField(formData[key]);
}
</code></pre>
<h2>Валидация формы: реальный краш-код</h2>
<p dir="auto">Возьми типичную задачу: проверить все поля формы перед сабмитом. Поля - объект {email, password, age}. Добавь прототип с методами валидации - и for…in словит их, пытаясь провалить toString как email.</p>
<p dir="auto">Без фильтра код выглядит innocently: for (key in formData) { if (!isValid(formData[key])) errors[key] = msg; }. Добавь прототип - и errors заполнится фигней вроде errors.toString = ‘not a string’. Форма не сабмитится по ложным ошибкам.</p>
<p dir="auto">Object.keys() решает: только реальные поля. Плюс в валидации учти типы ошибок: valueMissing, typeMismatch, patternMismatch - стандартные от HTML5, но в кастоме их эмулируй на своих полях.</p>
<p dir="auto">Таблица сравнения на примере формы:</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Подход</th>
<th>Поля</th>
<th>Прототип</th>
<th>Ошибки в валидации</th>
</tr>
</thead>
<tbody>
<tr>
<td>for…in</td>
<td>name, email</td>
<td><strong>toString, valueOf</strong></td>
<td>Ложные срабатывания</td>
</tr>
<tr>
<td>Object.keys() + for…of</td>
<td><strong>name, email</strong></td>
<td>Нет</td>
<td>Только поля формы</td>
</tr>
<tr>
<td>for…in + hasOwnProperty</td>
<td>name, email</td>
<td>Отфильтровано</td>
<td>Работает, но verbose</td>
</tr>
</tbody>
</table>
<ul>
<li><strong>Стандартные ошибки</strong>: valueMissing для пустых, typeMismatch для email без @.</li>
<li><strong>Кастом валидация</strong>: проверяй length, pattern - но только на своих ключах.</li>
<li><strong>Производительность</strong>: для 10 полей разница в памяти negligible, предсказуемость рулит.</li>
</ul>
<h2>Когда for…in все-таки юзать (редко)</h2>
<p dir="auto">for…in не мусор полностью. Полезен для introspection: проверить наличие свойств в объекте с прототипами или копировать shallow без lodash. Но в валидации? Забудь.</p>
<p dir="auto">Если объект чистый, без прототипов - ок. Но реальный код редко такой. Лучше привыкнуть к Object.keys() - меньше багов, меньше if’ов.</p>
<h2>Не полагайся на legacy-трюки</h2>
<p dir="auto">hasOwnProperty спасает for…in, но зачем boilerplate, когда Object.keys() решает чище? Подумай о destructuring или entries() - они еще гибче. А если форма большая, вынеси валидацию в WeakMap или Proxy - прототипы не проблема.</p>
<p dir="auto">В рефакторе увидишь: половина багов в формах от for…in. Перепиши на keys() + of - и спи спокойно. Осталось копнуть в итераторы глубже или Proxy для валидации on-the-fly.</p>
]]></description><link>https://forum.exlends.com/topic/2022/for...in-protiv-object.keys-for...of-pochemu-prototipy-lomayut-validaciyu-formy</link><generator>RSS for Node</generator><lastBuildDate>Tue, 07 Apr 2026 22:03:07 GMT</lastBuildDate><atom:link href="https://forum.exlends.com/topic/2022.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 07 Apr 2026 13:04:43 GMT</pubDate><ttl>60</ttl></channel></rss>