<?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[Map.getOrInsert в ECMAScript 2026: атомарные операции для Map]]></title><description><![CDATA[<p dir="auto"><img src="/assets/uploads/files/a2/88/68/1773744562805-generated_1773744524773-resized.webp" alt="Обложка: Map.getOrInsert в ECMAScript 2026: атомарные операции для Map" class=" img-fluid img-markdown" /></p>
<p dir="auto">В ECMAScript 2026 появились методы <strong>Map.getOrInsert</strong> и <strong>Map.getOrInsertComputed</strong>. Они упрощают работу с Map, позволяя получать значение по ключу или вставлять дефолтное, если ключа нет. Это решает проблему ручных проверок has/get/set, которые часто приводят к ошибкам в многопоточной среде или при частых обращениях.</p>
<p dir="auto">Такие атомарные операции ускоряют код и делают его чище. Особенно полезно для группировки данных, кэширования или инициализации структур. Забудьте о boilerplate - теперь всё в одном вызове.</p>
<h2>Как работает Map.getOrInsert</h2>
<p dir="auto">Метод <strong>getOrInsert(key, defaultValue)</strong> возвращает значение по ключу, если оно есть. Если ключа нет, вставляет defaultValue и возвращает его. Это атомарная операция - никаких race conditions между проверкой и вставкой.</p>
<p dir="auto">Раньше приходилось писать if (map.has(key)) return map.get(key); else map.set(key, defaultValue); return defaultValue;. Теперь всё в одном методе. Логика простая: поиск, вставка если нужно, возврат. Поддерживает любые ключи, сравнение по SameValue.</p>
<p dir="auto">Представьте группировку данных по ключам. Вместо проверок используем map.getOrInsert(key, []).push(value). Код короче и надёжнее. В спецификации ECMAScript 2026 это описано в разделе 24.1.3.7.</p>
<ul>
<li><strong>Преимущества getOrInsert</strong>:
<ul>
<li>Атомарность: вставка без промежуточных проверок.</li>
<li>Простота: заменяет 3-4 строки на одну.</li>
<li>Универсальность: работает с примитивными и объектными ключами.</li>
</ul>
</li>
</ul>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Традиционный подход</th>
<th>getOrInsert</th>
</tr>
</thead>
<tbody>
<tr>
<td>if (!map.has(key)) map.set(key, []); map.get(key).push(value);</td>
<td>map.getOrInsert(key, []).push(value);</td>
</tr>
<tr>
<td>Риск race condition в асинхронном коде</td>
<td>Атомарно, без риска</td>
</tr>
<tr>
<td>Длинный код</td>
<td>Одна строка</td>
</tr>
</tbody>
</table>
<h2>Map.getOrInsertComputed для ленивых вычислений</h2>
<p dir="auto"><strong>getOrInsertComputed(key, callback)</strong> похож на getOrInsert, но дефолтное значение вычисляется только если нужно. Callback получает key и возвращает значение. Идеально, когда создание дефолта дорогое - например, объект или массив с инициализацией.</p>
<p dir="auto">В отличие от getOrInsert, здесь callback вызывается лениво. Если ключ есть, ничего не считается. В спецификации шаги: проверка callable, поиск, вызов callback(key), вставка или обновление. Если во время callback Map изменился, обновляет существующую запись.</p>
<p dir="auto">Пример: группировка с дорогим дефолтом. map.getOrInsertComputed(key, () =&gt; new Set()).add(value). Экономит ресурсы, если ключ уже был. Логирует создание только при необходимости.</p>
<ul>
<li><strong>Когда использовать getOrInsertComputed</strong>:
<ul>
<li>Дефолт требует вычислений (объекты, массивы).</li>
<li>Частые вызовы с существующими ключами.</li>
<li>Избежать ненужных аллокаций.</li>
</ul>
</li>
</ul>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Метод</th>
<th>Вычисление дефолта</th>
<th>Пример</th>
</tr>
</thead>
<tbody>
<tr>
<td>getOrInsert</td>
<td>Всегда</td>
<td>map.getOrInsert(key, expensiveObject)</td>
</tr>
<tr>
<td>getOrInsertComputed</td>
<td>Только если нужно</td>
<td>map.getOrInsertComputed(key, k =&gt; expensiveObject(k))</td>
</tr>
</tbody>
</table>
<h2>Реальные сценарии и сравнение подходов</h2>
<p dir="auto">В повседневной разработке Map.getOrInsert упрощает кэш, группировку, инициализацию. Для фронтенда - хранение состояний по ID. На бэкенде - агрегация логов или метрик. Атомарность важна в Web Workers или Node.js с кластерами.</p>
<p dir="auto">Сравним с WeakMap: там тоже есть getOrInsert, но ключи - только объекты, сборка мусора автоматическая. Полезно для приватных данных. Старые паттерны вроде map.get(key) ?? default не атомарны и ломаются на null/undefined.</p>
<p dir="auto">Пример группировки:</p>
<pre><code class="language-javascript">const data = &lsqb;&lsqb;'a', 1], ['b', 2], ['a', 3&rsqb;&rsqb;;
const grouped = new Map();
for (let [key, value] of data) {
  grouped.getOrInsert(key, []).push(value);
}
console.log(grouped.get('a')); // [1, 3]
</code></pre>
<p dir="auto">Код короче, без if-else.</p>
<ul>
<li><strong>Сценарии применения</strong>:
<ul>
<li><em>Группировка массивов</em>: getOrInsert(key, []).</li>
<li><em>Кэш с дефолтом</em>: getOrInsertComputed(key, () =&gt; compute(key)).</li>
<li><em>Словари с инициализацией</em>: объекты по умолчанию.</li>
</ul>
</li>
</ul>
<h2>Почему это шаг вперёд в ECMAScript 2026</h2>
<p dir="auto">Эти методы закрывают пробелы в API Map, делая его конкурентным коллекциям других языков. Proposal-upsert от TC39 прошёл все стадии. Поддержка в Chrome 145+, Safari 26.2. Код становится declarative и менее подверженным ошибкам.</p>
<p dir="auto">Остаётся пространство для WeakMap-вариантов в продакшене и оптимизаций под V8. Стоит протестировать производительность на больших Map - атомарность может дать прирост в многопоточности.</p>
]]></description><link>https://forum.exlends.ru/topic/1692/map.getorinsert-v-ecmascript-2026-atomarnye-operacii-dlya-map</link><generator>RSS for Node</generator><lastBuildDate>Sat, 17 Oct 2026 03:52:42 GMT</lastBuildDate><atom:link href="https://forum.exlends.ru/topic/1692.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 17 Mar 2026 10:49:23 GMT</pubDate><ttl>60</ttl></channel></rss>