<?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[ECMAScript 2026: Math.sumPrecise и Map.getOrInsert]]></title><description><![CDATA[<p dir="auto"><img src="/assets/uploads/files/26/66/0e/1773813580735-generated_1773813531007-resized.webp" alt="Обложка: ECMAScript 2026: новые методы Math.sumPrecise и Map.getOrInsert для точных вычислений" class=" img-fluid img-markdown" /></p>
<p dir="auto">В этой статье разберёмся с двумя полезными методами, которые появились в ECMAScript 2026. Они решают реальные проблемы разработчиков: точность вычислений в финансовых приложениях и удобство работы с картами. Эти инструменты уже в спецификации и готовы к использованию.</p>
<p dir="auto">Методы простые, но мощные. Они экономят код, снижают ошибки и делают логику понятнее. Если вы работаете с JavaScript на боевом уровне, стоит знать, как они устроены и когда их применять.</p>
<h2>Проблема потери точности при суммировании</h2>
<p dir="auto">Когда вы складываете числа в JavaScript обычным способом, может случиться беда. Браузер работает с числами в формате float64, и при операциях теряется точность. Представьте финансовый калькулятор: пользователь вносит 100 долларов, программа теряет копейку, и в итоге вместо нужной суммы на счёте оказывается совсем другое число.</p>
<p dir="auto">Классический пример - вот такой код:</p>
<pre><code class="language-javascript">let values = [1e20, 0.1, -1e20];
let result = values.reduce((a, b) =&gt; a + b, 0);
console.log(result); // 0
</code></pre>
<p dir="auto">Хотя математически ответ должен быть 0.1, JavaScript вернёт 0. Дело в том, что число 1e20 настолько велико, что 0.1 просто теряется при округлении. Наивное суммирование игнорирует эту проблему, поскольку оперирует числами слева направо без учёта масштаба.</p>
<p dir="auto">Эта проблема критична для:</p>
<ul>
<li>Финансовых приложений, где каждая копейка на счёте</li>
<li>Научных расчётов с очень большими и очень маленькими числами</li>
<li>Статистических анализов и агрегирования данных</li>
<li>Любых вычислений, где точность - требование, а не опция</li>
</ul>
<h2>Math.sumPrecise - безошибочное суммирование</h2>
<p dir="auto">Метод <strong>Math.sumPrecise()</strong> решает эту задачу раз и навсегда. Он принимает iterable с числами и складывает их, используя специальный алгоритм, который максимально точен. Фактически, результат будет таким же, как если бы вы считали с произвольной точностью, а потом конвертировали обратно в float.</p>
<p dir="auto">Вот как это работает в реальности:</p>
<pre><code class="language-javascript">let values = [1e20, 0.1, -1e20];
let preciseResult = Math.sumPrecise(values);
console.log(preciseResult); // 0.1 - вот это правильно!
</code></pre>
<p dir="auto">Метод особенно полезен для приближения математических констант. Если вы считаете число e через степенной ряд:</p>
<pre><code class="language-javascript">function* sequenceOfE() {
  let member = 1;
  yield member;
  
  for (let i = 1; i &lt; 20; ++i) {
    member /= i;
    yield member;
  }
}

// Наивное суммирование
const regularSum = Array.from(sequenceOfE()).reduce((acc, cur) =&gt; acc + cur, 0);
console.log(regularSum); // 2.7182818284590455
console.log(Math.abs(Math.E - regularSum)); // 4.44e-16 - большая ошибка

// Точное суммирование
const preciseSum = Math.sumPrecise(sequenceOfE());
console.log(preciseSum); // 2.718281828459045
console.log(Math.abs(Math.E - preciseSum)); // 0 - идеально!
</code></pre>
<p dir="auto">Замечали ошибку в четвёртом знаке после запятой? Math.sumPrecise полностью её устраняет. Это достигается благодаря алгоритму из работы Shewchuk 1996 года, который обрабатывает переполнение и учитывает все детали floating point арифметики.</p>
<p dir="auto">Важные особенности метода:</p>
<ul>
<li>Работает <strong>только с числами</strong> - если передадите строку или объект, получите ошибку</li>
<li>Возвращает <strong>-0</strong> для пустого массива (это математически правильно, так как -0 - аддитивная единица в float64)</li>
<li>Работает <strong>медленнее</strong> наивного суммирования, потому что проводит больше вычислений</li>
<li><strong>Не поддерживает BigInt</strong> - только обычные Number</li>
</ul>
<p dir="auto">Примеры использования в реальном коде:</p>
<pre><code class="language-javascript">// Финансовые расчёты
const prices = [19.99, 29.99, 39.99, 10.01];
const total = Math.sumPrecise(prices); // Правильная сумма

// Агрегирование данных с датчиков
const measurements = [0.001, 0.002, 0.001, 0.0005];
const average = Math.sumPrecise(measurements) / measurements.length;

// Расчёт средневзвешенного значения
const weights = [100, 200, 150, 50];
const values = [1.5, 2.0, 1.8, 1.2];
const weighted = Math.sumPrecise(
  Array.from({ length: weights.length }, (_, i) =&gt; weights[i] * values[i])
) / Math.sumPrecise(weights);
</code></pre>
<h2>Когда использовать Math.sumPrecise</h2>
<p dir="auto">Не спешите заменять все reduce на sumPrecise - это замедлит код. Используйте метод если:</p>
<ol>
<li><strong>Точность критична</strong> - финансы, научные вычисления, медицина</li>
<li><strong>Большой диапазон чисел</strong> - микронаносекунды рядом с миллиардами</li>
<li><strong>Много операций суммирования</strong> - ошибки накапливаются</li>
<li><strong>Требования стандартов</strong> - GDPR, финрегулирование и подобные</li>
</ol>
<p dir="auto">Для простых случаев типа подсчёта элементов массива или суммирования ID обычный reduce будет быстрее и достаточно точен.</p>
<h2>Map.getOrInsert - удобство работы с картами</h2>
<p dir="auto">Вторая полезная штука - <strong>Map.prototype.getOrInsert()</strong>. Это метод, который одновременно проверяет наличие ключа и вставляет значение по умолчанию, если ключа нет. Вместо трёх операций - одна.</p>
<p dir="auto">До этого разработчики писали так:</p>
<pre><code class="language-javascript">const map = new Map();

if (map.has('key')) {
  return map.get('key');
} else {
  map.set('key', 'default');
  return 'default';
}

// Или через паттерн с nullish coalescing
map.set('key', map.get('key') ?? 'default');
return map.get('key');
</code></pre>
<p dir="auto">Теперь всё просто:</p>
<pre><code class="language-javascript">const value = map.getOrInsert('key', 'default');
</code></pre>
<p dir="auto">Метод работает так: если ключ найден, вернёт его значение. Если нет - вставит переданное значение и вернёт его. Это <strong>эквивалентно</strong> первому варианту выше, но читается как одна логичная операция.</p>
<p dir="auto">Есть и вариант с вычислением значения - <strong>Map.prototype.getOrInsertComputed()</strong>. Он принимает callback вместо значения и вызывает его только если ключ не найден. Это экономит вычисления, когда значение дорогое:</p>
<pre><code class="language-javascript">const map = new Map();

// Callback вызовётся только если ключ 'expensive' не существует
const result = map.getOrInsertComputed('expensive', (key) =&gt; {
  console.log('Вычисляю...');
  return heavyCalculation(key);
});
</code></pre>
<p dir="auto">Популярный паттерн - группировка элементов массива по ключам:</p>
<pre><code class="language-javascript">const items = [
  { category: 'fruit', name: 'apple' },
  { category: 'fruit', name: 'banana' },
  { category: 'vegetable', name: 'carrot' },
];

const grouped = new Map();

for (const item of items) {
  // Получаем или создаём пустой массив для категории
  grouped.getOrInsert(item.category, []).push(item);
}

console.log(grouped);
// Map {
//   'fruit' =&gt; [ { category: 'fruit', name: 'apple' }, ... ],
//   'vegetable' =&gt; [ { category: 'vegetable', name: 'carrot' } ]
// }
</code></pre>
<p dir="auto">Это гораздо читабельнее, чем если бы вы проверяли наличие ключа каждый раз вручную.</p>
<p dir="auto">Семейство методов включает также <strong>WeakMap.prototype.getOrInsert()</strong> и <strong>WeakMap.prototype.getOrInsertComputed()</strong> для работы с WeakMap. Используется редко, но логика та же.</p>
<h2>Практические примеры и сравнение</h2>
<p dir="auto">Примеры применения getOrInsert в боевом коде:</p>
<pre><code class="language-javascript">// Подсчёт частоты символов в строке
const string = "counting characters in a string";
const charCount = new Map();

for (const char of string) {
  const counter = charCount.getOrInsert(char, { char, count: 0 });
  counter.count++;
}

console.log(charCount);
</code></pre>
<pre><code class="language-javascript">// Кэширование результатов дорогих операций
const cache = new Map();

function expensiveOperation(key) {
  return cache.getOrInsertComputed(key, (k) =&gt; {
    // Долгое вычисление
    return complexCalculation(k);
  });
}
</code></pre>
<pre><code class="language-javascript">// Граф смежности (граф для сетевых алгоритмов)
const graph = new Map();

function addEdge(from, to) {
  graph.getOrInsert(from, []).push(to);
  graph.getOrInsert(to, []).push(from);
}
</code></pre>
<p dir="auto">Сравним старый и новый подходы:</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Задача</th>
<th>Старый способ</th>
<th>С getOrInsert</th>
</tr>
</thead>
<tbody>
<tr>
<td>Получить или создать</td>
<td>3-4 строки кода</td>
<td>1 строка</td>
</tr>
<tr>
<td>Вычислить только если нужно</td>
<td>Условие + вычисление</td>
<td>1 вызов с callback</td>
</tr>
<tr>
<td>Читаемость</td>
<td>Средняя</td>
<td>Высокая</td>
</tr>
<tr>
<td>Производительность</td>
<td>Одинаковая</td>
<td>Одинаковая</td>
</tr>
<tr>
<td>Синтаксическая сахаристость</td>
<td>Низкая</td>
<td>Высокая</td>
</tr>
</tbody>
</table>
<p dir="auto">В WeakMap ситуация особенная:</p>
<pre><code class="language-javascript">const domNodeData = new WeakMap();
const node = document.getElementById('myNode');

// Старый способ - можно потерять ссылку
if (!domNodeData.has(node)) {
  domNodeData.set(node, { listeners: [] });
}

// Новый способ - безопаснее
const data = domNodeData.getOrInsert(node, { listeners: [] });
data.listeners.push(handler);
</code></pre>
<h2>Мелкие детали, которые важны</h2>
<p dir="auto">Метод getOrInsert <strong>не перезаписывает существующие значения</strong>. Это критично, потому что иногда в Map лежат null или undefined, и вы хотите их сохранить. Способ старый (с нулишь coalasing) может коварно перезаписать значение:</p>
<pre><code class="language-javascript">const map = new Map(&lsqb;&lsqb;'key', undefined&rsqb;&rsqb;);

// Старый способ - ОШИБКА!
map.set('key', map.get('key') ?? 'default');
console.log(map.get('key')); // 'default' - потеряли undefined!

// Новый способ - правильно
const value = map.getOrInsert('key', 'default');
console.log(value); // undefined - сохранили!
</code></pre>
<p dir="auto">Оба метода (getOrInsert и getOrInsertComputed) работают с <strong>любыми объектами как ключами</strong> - это полезно для Map:</p>
<pre><code class="language-javascript">const objKey = { id: 1 };
const map = new Map();

const data = map.getOrInsert(objKey, { count: 0 });
data.count++;

console.log(map.get(objKey)); // { count: 1 }
</code></pre>
<p dir="auto">Но запомните: <strong>ключи в Map сравниваются по ссылке для объектов</strong>. Два разных объекта с одинаковыми свойствами - это разные ключи.</p>
<p dir="auto">Производительность getOrInsert не хуже, чем старый способ. Это просто <strong>удобство и безопасность</strong>. Не придётся беспокоиться о перезаписи null и undefined.</p>
<h2>Когда эти методы точно помогут</h2>
<p dir="auto">Используйте <strong>Math.sumPrecise</strong>, если:</p>
<ul>
<li>Работаете с финансами или денежными единицами</li>
<li>Складываете очень большие и маленькие числа</li>
<li>Нужна гарантированная точность для отчётов</li>
<li>Требования регулятора или стандарта</li>
</ul>
<p dir="auto">Используйте <strong>Map.getOrInsert</strong>, если:</p>
<ul>
<li>Часто проверяете наличие и вставляете значение</li>
<li>Строите группировки, кэши, графы</li>
<li>Хотите понятнее читать код</li>
<li>Боитесь случайно перезаписать null или undefined</li>
</ul>
<p dir="auto">Безопасность и удобство идут рука об руку в этих методах. Они не добавляют магии, а решают типичные задачи минимальным и очевидным кодом.</p>
<h2>Поддержка браузерами и будущее</h2>
<p dir="auto">Оба метода уже в спецификации ECMAScript 2026 и готовы к использованию в современных JavaScript движках. Однако важная оговорка: <strong>Math.sumPrecise имеет ограниченную поддержку</strong>, поэтому в production коде будьте осторожны и проверяйте, доступен ли метод.</p>
<p dir="auto">Для getOrInsert поддержка лучше, но всё равно стоит добавить полифилл для старых браузеров, если вы поддерживаете Internet Explorer или древние версии.</p>
<p dir="auto">В будущем эти методы станут стандартом, и разработчики смогут писать код безопаснее и быстрее. Сейчас уже стоит с ними познакомиться и применять где уместно. Эти небольшие удобства экономят часы отладки и снижают количество багов в production.</p>
]]></description><link>https://forum.exlends.ru/topic/1714/ecmascript-2026-math.sumprecise-i-map.getorinsert</link><generator>RSS for Node</generator><lastBuildDate>Sat, 17 Oct 2026 03:26:01 GMT</lastBuildDate><atom:link href="https://forum.exlends.ru/topic/1714.rss" rel="self" type="application/rss+xml"/><pubDate>Wed, 18 Mar 2026 05:59:42 GMT</pubDate><ttl>60</ttl></channel></rss>