<?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[Object.entries + fromEntries vs for: трансформация объектов фильтрами в поиске товаров]]></title><description><![CDATA[<p dir="auto">Часто в динамическом поиске товаров нужно фильтровать объект параметров - цена, категория, бренд. Классический <strong>for…in</strong> тянет прототипы и морочит голову. А <strong>Object.entries() + fromEntries()</strong> дают чистый массив пар ключ-значение, чтобы крутить фильтры через array methods без костылей.</p>
<p dir="auto">Это ускорит код, уберет утечки в итерациях и сделает его читаемым. Разберем на примере каталога товаров, где объект фильтров трансформируется под ввод юзера. Проблема знакомая: мидлы пишут циклы, а бандл раздувается от лишних проверок.</p>
<h2>Почему for…in - это легаси-ловушка</h2>
<p dir="auto">Код с <strong>for…in</strong> кажется простым, но под капотом он шарит по прототипам. В объекте фильтров товаров {price: {min: 100}, category: ‘electronics’} цикл потянет toString, hasOwnProperty и прочий мусор. В итоге - лишние if (obj.hasOwnProperty(key)), которые забывают. А в большом проекте это баги на прототипах.</p>
<p dir="auto">Object.entries() режет только own свойства в массив [[‘price’, {min:100}], [‘category’, ‘electronics’]]. Фильтры на array methods - filter, map - летят без тормозов. fromEntries() собирает обратно в объект. В динамическом поиске это идеал: ввел ‘cheap’ - отфильтровал price, собрал новый объект.</p>
<ul>
<li><strong>Прототипный мусор</strong>: for…in тянет Object.prototype, entries() - нет.</li>
<li><strong>Array methods</strong>: filter(([key, value]) =&gt; …) работает на ура, for требует деструкцию вручную.</li>
<li><strong>Производительность</strong>: entries/fromEntries быстрее в V8 для трансформаций, for - для простого перебора.</li>
</ul>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Сравнение</th>
<th>for…in</th>
<th>entries + fromEntries</th>
</tr>
</thead>
<tbody>
<tr>
<td>Прототипы</td>
<td>Тянет</td>
<td>Игнорирует</td>
</tr>
<tr>
<td>Фильтры</td>
<td>if внутри</td>
<td>Array.filter()</td>
</tr>
<tr>
<td>Читаемость</td>
<td>Средне</td>
<td>Высокая</td>
</tr>
<tr>
<td>Бандл</td>
<td>Минимум</td>
<td>Минимум (нативно)</td>
</tr>
</tbody>
</table>
<h2>Фильтрация по цене: entries в деле</h2>
<p dir="auto">Представь объект filters = {minPrice: 500, maxPrice: 2000, brand: ‘Samsung’}. Юзер ввел ‘expensive’ - нужно поднять minPrice до 1500. С <strong>Object.entries(filters)</strong> получаем массив, мапим price-значения, fromEntries() - назад в объект. Без мутаций, чисто функционально.</p>
<p dir="auto">В цикле for пришлось бы obj[key] = newValue с проверками типов. А здесь chain: entries -&gt; map -&gt; fromEntries. В поиске товаров это трансформирует фильтры под слайдер цены или debounce-input. <em>Нюанс: дубли ключей в fromEntries перезаписываются последним</em> - полезно для merge.</p>
<pre><code class="language-javascript">const filters = {minPrice: 500, maxPrice: 2000, brand: 'Samsung'};
const expensiveFilters = Object.fromEntries(
  Object.entries(filters).map(([key, value]) =&gt; {
    if (key.includes('Price')) {
      return [key, {min: 1500, max: value.max || 5000}];
    }
    return [key, value];
  })
);
// {minPrice: {min:1500, max:2000}, maxPrice: {min:1500, max:5000? wait no}, brand: 'Samsung'}
</code></pre>
<ul>
<li><strong>Шаг 1</strong>: entries() -&gt; [[‘minPrice’,500], …]</li>
<li><strong>Шаг 2</strong>: map с условием на key.startsWith(‘min’)</li>
<li><strong>Шаг 3</strong>: fromEntries() -&gt; новый объект без мутаций.</li>
<li><strong>Бонус</strong>: Добавь .filter(([key]) =&gt; !key.startsWith(‘ignore’)) для удаления полей.</li>
</ul>
<h2>Динамический поиск по категориям и брендам</h2>
<p dir="auto">В каталоге товаров объект {category: ‘phones’, brand: [‘Samsung’,‘Apple’], inStock: true}. Поиск ‘laptops’ - нужно обновить category, добавить rating &gt; 4. entries() разворачивает в массив, где легко фильтровать бренды или мержить новые.</p>
<p dir="auto">С for пришлось бы nested if для каждого типа. А chain entries.filter/map/fromEntries - универсал. Для debounce-поиска это цепочка: userInput -&gt; match -&gt; transform key/value -&gt; новый объект. <em>Внимание: символы-ключей сохраняются через fromEntries</em>, строки только entries().</p>
<pre><code class="language-javascript">const searchFilters = {
  category: 'phones',
  brands: ['Samsung'],
  rating: {min: 3}
};

const laptopFilters = Object.fromEntries(
  Object.entries(searchFilters)
    .filter(([key]) =&gt; key !== 'brands') // убираем старые бренды
    .map(([key, val]) =&gt; {
      if (key === 'category') return [key, 'laptops'];
      if (key === 'rating') return [key, {min: 4}];
      return [key, val];
    })
);
</code></pre>
<ul>
<li><strong>Фильтр ключей</strong>: .filter(([key]) =&gt; key !== ‘temp’)</li>
<li><strong>Трансформ значений</strong>: map с деструкцией</li>
<li><strong>Мерж с дефолтами</strong>: entries(defaults).concat(newPairs) -&gt; fromEntries</li>
</ul>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Задача</th>
<th>for…in код строк</th>
<th>entries chain код строк</th>
</tr>
</thead>
<tbody>
<tr>
<td>Фильтр price</td>
<td>8-10</td>
<td>4-5</td>
</tr>
<tr>
<td>Обновить category</td>
<td>6</td>
<td>3</td>
</tr>
<tr>
<td>Мерж объектов</td>
<td>12+</td>
<td>5</td>
</tr>
</tbody>
</table>
<h2>Трансформация множественных фильтров в цепочке</h2>
<p dir="auto">Сложный кейс: объект с nested {priceRange: {min,max}, tags: []}. Динамический ввод ‘tag:premium’ - распарсить, добавить в tags. entries() + array extras (flatMap?) + fromEntries - идеально. Цикл бы утонул в if/else.</p>
<p dir="auto">Это масштабируется на API-запросы: трансформируй filters в query params. В React/Vue state updater - чистый reducer. <em>Грабли: fromEntries не клонирует глубоко nested, используй structuredClone если надо</em>.</p>
<pre><code class="language-javascript">const complexFilters = {
  priceRange: {min: 100, max: 1000},
  tags: ['new'],
  stock: true
};

const premiumFilters = Object.fromEntries(
  Object.entries(complexFilters).flatMap(([key, val]) =&gt; {
    if (key === 'tags') {
      return [['tags', [...val, 'premium']]];
    }
    return [[key, val]];
  })
);
</code></pre>
<ul>
<li><strong>Nested update</strong>: flatMap для добавления пар</li>
<li><strong>Удаление</strong>: .filter перед map</li>
<li><strong>Валидация</strong>: map с try/catch на value</li>
</ul>
<h2>Масштаб на реальный магазинный поиск</h2>
<p dir="auto">Когда фильтров 10+ (цвет, размер, доставка), chain entries/fromEntries - спасение от boilerplate. Добавь reduce для custom logic. Циклы хороши для side-effects, но трансформы - нативно.</p>
<p dir="auto">Под капотом V8 оптимизирует array methods лучше, чем for с объектами. В продакшене это меньше памяти в ивент-лупе. <em>Осталось: polyfill для старых браузеров, но в 2026 - не актуал</em>.</p>
<p dir="auto"><strong>Когда брать for</strong>: Простой перебор без трансформа. <strong>Entries chain</strong>: Любые фильтры/мапы. Тестируй на 1000 items - разница в ms, но код чище в 2x.</p>
<h2>Итог под hood: выбирай по задаче</h2>
<p dir="auto">Entries + fromEntries выигрывают в 80% трансформаций объектов - короче, быстрее, без прототипов. For держи для raw итераций. В поиске товаров это решает debounce, слайдеры, мержи.</p>
<p dir="auto">За кадром - комбо с Map/Set для уникальных ключей или Lodash без него. Подумай, как впихнуть в твой state manager без лишних deps.</p>
]]></description><link>https://forum.exlends.com/topic/2056/object.entries-fromentries-vs-for-transformaciya-obuektov-filtrami-v-poiske-tovarov</link><generator>RSS for Node</generator><lastBuildDate>Tue, 14 Apr 2026 23:50:01 GMT</lastBuildDate><atom:link href="https://forum.exlends.com/topic/2056.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 14 Apr 2026 06:05:25 GMT</pubDate><ttl>60</ttl></channel></rss>