<?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">Недавно в ECMAScript 2026 добавили два новых метода для работы с Map и WeakMap - getOrInsert и getOrInsertComputed. Это не просто очередное расширение API, а решение реальной проблемы, с которой сталкиваются разработчики каждый день. Методы упрощают код, делают его понятнее и избавляют от лишних проверок.</p>
<p dir="auto">Если вы когда-нибудь писали логику типа “проверь, есть ли ключ в Map, если нет - создай значение” - эта статья для вас. Разберёмся, как это работает, когда это использовать и как это изменит нашу повседневную работу с JavaScript.</p>
<h2>Проблема, которую решают новые методы</h2>
<p dir="auto">Представьте, что вам нужно собрать данные по группам. Например, у вас есть список продаж, и вы хотите сгруппировать их по категориям. До появления getOrInsert код выглядел вот так:</p>
<pre><code class="language-javascript">let grouped = new Map();
for (let [key, ...values] of data) {
  if (grouped.has(key)) {
    grouped.get(key).push(...values);
  } else {
    grouped.set(key, values);
  }
}
</code></pre>
<p dir="auto">Видите, как много здесь проверок? Сначала смотрим has(), потом get(), потом set(). Код не сложный, но его приходится писать снова и снова. Это похоже на ситуацию с Java и методами computeIfAbsent - разработчики годами просили что-то подобное.</p>
<p dir="auto"><strong>Основные неудобства старого подхода:</strong></p>
<ul>
<li>Нужно писать три операции вместо одной (has, get, set)</li>
<li>Код выглядит многословным и нарушает DRY-принцип</li>
<li>Легко сделать ошибку или забыть одну из проверок</li>
<li>Ключ проверяется дважды - при has() и при get()</li>
<li>В Map выполняется несколько поисков вместо одного</li>
</ul>
<h2>getOrInsert - простое и понятное решение</h2>
<p dir="auto">Теперь с getOrInsert то же самое выглядит намного чище:</p>
<pre><code class="language-javascript">let grouped = new Map();
for (let [key, ...values] of data) {
  grouped.getOrInsert(key, []).push(...values);
}
</code></pre>
<p dir="auto">Одна строка вместо четырёх! Метод работает очень просто: если ключ уже есть в Map, он возвращает существующее значение. Если нет - вставляет новое значение и возвращает его. В обоих случаях вы получаете значение, с которым можете работать дальше.</p>
<p dir="auto"><strong>Как работает getOrInsert:</strong></p>
<ul>
<li>Проверяет наличие ключа в Map</li>
<li>Если ключ найден - возвращает его значение</li>
<li>Если ключа нет - устанавливает переданное значение как дефолт</li>
<li>Возвращает значение в любом случае</li>
<li>Всё это происходит как одна атомарная операция</li>
</ul>
<p dir="auto">Это особенно удобно для накопления данных. Вместо проверок и условных операторов вы просто получаете значение, которое гарантированно существует.</p>
<h2>getOrInsertComputed - когда дефолт вычисляется дорого</h2>
<p dir="auto">А что если создание дефолтного значения - это сложная или дорогостоящая операция? Например, вам нужно инициализировать большой массив или запустить какое-то вычисление. Отправлять ресурсы впустую - глупо.</p>
<p dir="auto">Для этого есть getOrInsertComputed. Вместо готового значения вы передаёте функцию, которая будет вызвана только если ключа нет в Map:</p>
<pre><code class="language-javascript">let grouped = new Map();
for (let [key, ...values] of data) {
  grouped.getOrInsertComputed(key, () =&gt; []).push(...values);
}
</code></pre>
<p dir="auto">Отличие в деталях: вы передаёте стрелочную функцию вместо готового массива. Эта функция вызывается <strong>только если ключа нет</strong>. Если ключ уже существует - функция не выполняется вообще.</p>
<p dir="auto"><strong>Когда это особенно полезно:</strong></p>
<ul>
<li>Когда дефолтное значение требует вычислений или I/O операций</li>
<li>Для ленивой инициализации сложных структур данных</li>
<li>При работе с кешами или кэшированием значений</li>
<li>Когда создание значения может быть дорогостоящим процессом</li>
<li>В случаях, когда значение зависит от внешнего состояния</li>
</ul>
<p dir="auto">Кроме того, getOrInsertComputed работает с WeakMap тем же способом - вы получаете одну операцию вместо нескольких проверок.</p>
<h2>Сравнение подходов</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Подход</th>
<th>Готовое значение</th>
<th>Ленивое вычисление</th>
<th>Использование</th>
<th>Производительность</th>
</tr>
</thead>
<tbody>
<tr>
<td>Старый способ (has/get/set)</td>
<td>✓</td>
<td>Нет встроенного способа</td>
<td>Везде</td>
<td>Несколько поисков в таблице</td>
</tr>
<tr>
<td>getOrInsert()</td>
<td>✓</td>
<td>✗</td>
<td>Простые значения</td>
<td>Один поиск в таблице</td>
</tr>
<tr>
<td>getOrInsertComputed()</td>
<td>✗</td>
<td>✓</td>
<td>Дорогие вычисления</td>
<td>Один поиск + условное вычисление</td>
</tr>
</tbody>
</table>
<p dir="auto">Видите разницу? Новые методы заменяют целый паттерн кода, который раньше требовал либо множества строк, либо обёрток в функции. Это как перейти с для цикла на forEach - удобнее, понятнее и безопаснее.</p>
<h2>Практические примеры использования</h2>
<p dir="auto">Давайте посмотрим, где эти методы особенно помогают. Первый пример - счётчик событий:</p>
<pre><code class="language-javascript">const eventCounts = new Map();

function logEvent(eventName) {
  const count = eventCounts.getOrInsert(eventName, 0);
  eventCounts.set(eventName, count + 1);
}
</code></pre>
<p dir="auto">Здесь getOrInsert гарантирует, что вы всегда получите число, даже если это первое событие.</p>
<p dir="auto">Второй пример - кэш с ленивой инициализацией:</p>
<pre><code class="language-javascript">const userCache = new WeakMap();

function getUserData(user) {
  return userCache.getOrInsertComputed(user, () =&gt; {
    // Это выполнится только если user не в кэше
    return fetchUserDataFromDatabase(user);
  });
}
</code></pre>
<p dir="auto">Здесь вы не тратите ресурсы на запросы к базе для пользователей, которые уже в кэше.</p>
<p dir="auto">Третий пример - построение индекса данных:</p>
<pre><code class="language-javascript">const index = new Map();

for (const item of items) {
  const bucket = index.getOrInsert(item.type, () =&gt; []);
  bucket.push(item);
}
</code></pre>
<p dir="auto">Это очень чистый и понятный способ сгруппировать элементы по типам.</p>
<p dir="auto"><strong>Реальные сценарии применения:</strong></p>
<ul>
<li>Подсчёт статистики и метрик в приложении</li>
<li>Построение индексов и инвертированных индексов для поиска</li>
<li>Кэширование вычисленных значений или результатов запросов</li>
<li>Агрегация данных из разных источников</li>
<li>Построение графов зависимостей между объектами</li>
<li>Инициализация данных по требованию в сложных структурах</li>
</ul>
<h2>Совместимость и поддержка браузерами</h2>
<p dir="auto">ЭТИ методы уже включены в ECMAScript 2026, что означает, что браузеры и рантаймы начнут поддерживать их прямо сейчас. Chrome уже добавил поддержку, и другие движки последуют вскоре.</p>
<p dir="auto">Но важный момент - если вам нужна поддержка старых браузеров, вы можете использовать полифиллы. Например, core-js предоставляет реализацию этих методов для более старых сред. Логика полифилла простая - он проверяет, есть ли уже встроенные методы, и если нет, добавляет свои реализации.</p>
<p dir="auto"><strong>Сроки поддержки:</strong></p>
<ul>
<li>ECMAScript 2026 спецификация: уже финализирована</li>
<li>Chrome и Chromium: поддержка начата</li>
<li>Firefox: поддержка планируется</li>
<li>Safari: поддержка планируется</li>
<li>Node.js: будет добавлена в ближайших версиях</li>
</ul>
<p dir="auto">Если вы работаете с TypeScript, типы для этих методов уже включены в свежие версии типов DOM и ECMAScript.</p>
<h2>Атомарность операций</h2>
<p dir="auto">Одно из ключевых достоинств этих методов - они выполняются как <strong>единая операция</strong>. Это важно, потому что код становится проще и понятнее. Вы не рискуете потерять данные между проверкой и устанавливанием значения, если что-то пойдёт не так.</p>
<p dir="auto">Хотя JavaScript однопоточный, поэтому race conditions из многопоточных языков здесь невозможны, эти методы всё равно полезны. Они гарантируют, что логика “получи или создай” выполнится как единое целое, без промежуточных состояний.</p>
<p dir="auto"><strong>Почему это важно:</strong></p>
<ul>
<li>Код не может быть прерван между проверкой и установкой</li>
<li>Нет мёртвого кода с проверками, которые никогда не выполнятся</li>
<li>Легче отладить логику без множества условных переходов</li>
<li>Производительность выше - один поиск в таблице вместо нескольких</li>
</ul>
<h2>Родство с методами других языков</h2>
<p dir="auto">Это не новая идея - похожие методы уже давно существуют в других языках. Java имеет computeIfAbsent и computeIfPresent, Scala предлагает getOrElseUpdate. Теперь JavaScript наконец-то ловит поезд.</p>
<p dir="auto">Но JavaScript выбрал собственный путь, создав два метода вместо одного. getOrInsert работает с готовыми значениями, а getOrInsertComputed - с функциями. Это разделение ответственности делает API чище и проще в понимании.</p>
<p dir="auto">Когда вы видите getOrInsert, вы сразу знаете, что тут просто передача готового значения. А getOrInsertComputed - это лениво вычисляемое значение. Нет размытости в коде.</p>
<h2>Что дальше?</h2>
<p dir="auto">Эти методы - результат многолетних дискуссий в сообществе разработчиков. Предложение начиналось с GitHub, обсуждалось в TC39, и теперь стало частью стандарта. Это показывает, как работает процесс эволюции JavaScript.</p>
<p dir="auto">Ваша задача как разработчика - начать использовать эти методы в своих проектах, когда это имеет смысл. Они не волшебная палочка, но для работы с Map и WeakMap это явный шаг вперёд. Код становится понятнее, короче и менее подвержен ошибкам. А это всегда хорошо.</p>
]]></description><link>https://forum.exlends.ru/topic/991/map.getorinsert-v-ecmascript-2026-atomarnye-operacii-dlya-map</link><generator>RSS for Node</generator><lastBuildDate>Sat, 17 Oct 2026 03:25:56 GMT</lastBuildDate><atom:link href="https://forum.exlends.ru/topic/991.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 03 Mar 2026 13:46:51 GMT</pubDate><ttl>60</ttl></channel></rss>