Перейти к содержанию
  • Лента
  • Категории
  • Последние
  • Метки
  • Популярные
  • Пользователи
  • Группы
Свернуть
exlends
Категории
  1. Главная
  2. Категории
  3. Языки программирования
  4. JavaScript
  5. Map.prototype.getOrInsert: атомарные операции для словарей в ECMAScript 2026

Map.prototype.getOrInsert: атомарные операции для словарей в ECMAScript 2026

Запланировано Прикреплена Закрыта Перенесена JavaScript
mapecmascript 2026getorinsert
1 Сообщения 1 Постеры 54 Просмотры
  • Сначала старые
  • Сначала новые
  • По количеству голосов
Ответить
  • Ответить, создав новую тему
Авторизуйтесь, чтобы ответить
Эта тема была удалена. Только пользователи с правом управления темами могут её видеть.
  • hannadevH Не в сети
    hannadevH Не в сети
    hannadev
    написал в отредактировано
    #1

    JavaScript развивается, и с выходом ECMAScript 2026 разработчикам доступна долгожданная функция для работы с Map объектами. Если вы устали писать одинаковый код для проверки наличия ключа и вставки значения, то getOrInsert() решит эту проблему в несколько символов.

    Данная статья разберёт, как работает новый метод, зачем он нужен и как его применять в реальных проектах. Мы посмотрим на практические примеры, сравним старый и новый подходы, а также поговорим о том, когда стоит использовать вычисляемую версию метода.

    Что такое getOrInsert и почему это важно

    Метод getOrInsert() - это комбинированная операция для Map, которая делает две вещи за раз: проверяет наличие ключа и возвращает его значение, или, если ключа нет, добавляет новую пару и возвращает добавленное значение. Звучит просто, но на практике это экономит огромное количество строк кода.

    До появления getOrInsert() разработчики были вынуждены писать условные проверки каждый раз, когда требовалось инициализировать значение в Map. Это не только увеличивало объём кода, но и делало его менее читаемым. Новый метод стал результатом долгих обсуждений в сообществе TC39 и включён в официальную спецификацию ECMAScript 2026.

    Основной синтаксис метода:

    map.getOrInsert(key, defaultValue)
    

    Метод возвращает значение, связанное с ключом, или defaultValue, если ключ не существовал. При этом происходит только одна операция поиска, что делает метод эффективнее нескольких вызовов has() и get().

    Сравнение старого и нового подходов

    Чтобы лучше понять пользу от getOrInsert(), давайте посмотрим, как раньше приходилось работать с инициализацией значений в Map. Классический пример - подсчёт количества символов в строке. Нужно пройти по каждому символу, создать для него счётчик, если его нет, и увеличить значение.

    Вот как это выглядело без нового метода:

    const string = "counting characters in a string";
    const map = new Map();
    
    for (const character of string) {
      let counterObj = map.get(character);
    
      if (!counterObj) {
        counterObj = {
          character,
          count: 0,
        };
        map.set(character, counterObj);
      }
    
      counterObj.count++;
    }
    

    А вот как это же выглядит с getOrInsert():

    const string = "counting characters in a string";
    const map = new Map();
    
    for (const character of string) {
      const counterObj = map.getOrInsert(character, {
        character,
        count: 0,
      });
    
      counterObj.count++;
    }
    

    Сравнение двух подходов:

    Аспект Старый подход getOrInsert()
    Количество строк 10+ строк 5 строк
    Читаемость Низкая, много условных проверок Высокая, понятна сразу
    Производительность Две операции поиска Одна операция поиска
    Переиспользование значения Требует переменной counterObj Возвращает значение напрямую

    Экономия кода может показаться небольшой, но когда вы работаете с несколькими Map объектами в большом приложении, разница становится заметной.

    Практические примеры использования

    Вот несколько типичных сценариев, где getOrInsert() особенно полезен.

    Группировка данных по ключам

    Часто нужно собрать элементы в группы на основе какого-то критерия. Без нового метода это требует проверки наличия массива и его инициализации. С getOrInsert() это становится одной строкой:

    const data = [["apple", "red", "sweet"], ["banana", "yellow", "sweet"], ["apple", "green"]];
    const grouped = new Map();
    
    for (const [key, ...values] of data) {
      grouped.getOrInsert(key, []).push(...values);
    }
    

    Инициализация конфигураций

    Когда работаете с конфигурационными объектами, часто нужно установить значения по умолчанию для отсутствующих ключей. getOrInsert() идеально подходит для этого:

    const options = readConfig();
    options.getOrInsert("theme", "light");
    options.getOrInsert("fontSize", 14);
    options.getOrInsert("language", "en");
    
    document.body.dataset.theme = options.get("theme");
    

    Счётчики и аккумуляторы

    В аналитике часто требуется подсчитывать события. Map с getOrInsert() позволяет избежать вложенных условных операторов:

    const events = ["click", "scroll", "click", "hover", "click"];
    const counters = new Map();
    
    for (const event of events) {
      const counter = counters.getOrInsert(event, 0);
      counters.set(event, counter + 1);
    }
    

    getOrInsertComputed() - когда вычисление дорогое

    Есть тонкость: в примерах выше мы всегда создаём объект по умолчанию, даже если ключ уже существует в Map. Если создание этого значения требует сложных вычислений или обращений к API, это неэффективно. Для таких случаев существует getOrInsertComputed(), который принимает функцию-обработчик вместо готового значения.

    Метод вычисляет значение только если ключа нет, что экономит ресурсы в циклах с большим количеством повторений. Функция получает ключ как аргумент, что иногда полезно для вычисления значения на основе самого ключа.

    const string = "counting characters in a string";
    const map = new Map();
    
    for (const character of string) {
      const counterObj = map.getOrInsertComputed(character, () => ({
        character,
        count: 0,
      }));
    
      counterObj.count++;
    }
    

    Когда использовать каждый метод:

    • Используйте getOrInsert(), если значение по умолчанию простое, быстро создаётся или уже готово.
    • Используйте getOrInsertComputed(), если вычисление значения требует времени: запрос к БД, сложный расчёт, создание тяжёлого объекта.

    Вот пример с дорогостоящим вычислением:

    const cache = new Map();
    
    function getUser(userId) {
      return cache.getOrInsertComputed(userId, () => {
        // Это выполнится только один раз для каждого userId
        return fetchUserFromDatabase(userId);
      });
    }
    

    Как это работает под капотом

    Спецификация ECMAScript 2026 описывает getOrInsert() как операцию, эквивалентную следующему коду:

    if (map.has(key)) {
      return map.get(key);
    }
    map.set(key, defaultValue);
    return defaultValue;
    

    Это может показаться, что метод делает две операции поиска, но на самом деле реализация браузеров оптимизирует это так, чтобы произошёл только один поиск в конечном счёте. Это внутренняя оптимизация, благодаря которой метод эффективнее вызова has() + get() + set() по отдельности.

    Важные детали реализации:

    • Метод работает с каноническим представлением ключа, то есть -0 и +0 рассматриваются как одинаковые ключи.
    • Если значение null или undefined - это полноценные значения, которые сохраняются в Map без проблем.
    • Метод вызывает все необходимые проверки типов, поэтому вызов на объекте без внутреннего слота [[MapData]] выбросит ошибку.
    • В отличие от простого присваивания map.set(key, map.get(key) ?? defaultValue), getOrInsert() работает корректно, даже если в Map хранятся null или undefined.

    Состояние поддержки и перспективы

    Метод включён в официальную спецификацию ECMAScript 2026, но его поддержка в браузерах и инструментах варьируется. На момент выхода новой версии спецификации основные браузеры начали добавлять поддержку, но полная совместимость ещё наращивается.

    Для использования в старых окружениях можно применить полифилл - простую реализацию, которая добавит метод, если его нет. Вот базовая версия:

    if (!Map.prototype.getOrInsert) {
      Map.prototype.getOrInsert = function(key, defaultValue) {
        if (!this.has(key)) {
          this.set(key, defaultValue);
        }
        return this.get(key);
      };
    }
    

    Статус поддержки варьируется:

    • Современные версии Chrome, Firefox и Safari уже поддерживают метод.
    • Некоторые инструменты сборки, такие как TypeScript, могут требовать обновления типов для корректного распознавания метода.
    • Node.js добавляет поддержку с выходом новых версий.
    • Для совместимости с полифиллом стоит использовать проверку if (!Map.prototype.getOrInsert) перед добавлением.

    На что обратить внимание при переходе на новый метод

    Переход на getOrInsert() в существующих проектах - это задача рефакторинга, которая требует внимательности. Нужно убедиться, что вы правильно понимаете семантику кода, который заменяете.

    Основная трудность - это случаи, когда ключ существует, но его значение - это null или undefined. В старом коде с условной проверкой такие значения часто заменялись на значение по умолчанию. С getOrInsert() существующее значение будет возвращено как есть, что может привести к неожиданному поведению, если логика полагалась на замену нулевых значений.

    // Старый код
    let value = map.get(key) ?? defaultValue;
    
    // Новый код
    let value = map.getOrInsert(key, defaultValue); // Вернёт null, если он был в map
    

    Так что при рефакторинге проверьте, есть ли в вашем Map значения null или undefined, которые должны обрабатываться иначе. Если нет - переход безопасен и улучшит читаемость кода.

    Последствия для архитектуры и дизайна

    Внедрение getOrInsert() изменяет не только стиль написания кода, но и повлияет на общие практики работы с Map в JavaScript. Функция стимулирует разработчиков полагаться на Map вместо обычных объектов для хранения ассоциативных данных, поскольку теперь работа с ними стала проще и понятнее.

    Это может привести к сдвигу в экосистеме: всё больше новых библиотек и фреймворков будут использовать Map как основной инструмент для структур данных. Старые паттерны вроде создания объектов с использованием циклов и условных проверок будут постепенно вытеснены более чистыми решениями. Код станет более функциональным и выразительным, что улучшит его поддерживаемость.

    1 ответ Последний ответ
    0

    Здравствуйте! Похоже, вас заинтересовала эта беседа, но у вас ещё нет аккаунта.

    Надоело каждый раз пролистывать одни и те же посты? Зарегистрировав аккаунт, вы всегда будете возвращаться на ту же страницу, где были раньше, и сможете выбирать, получать ли уведомления о новых ответах (по электронной почте или в виде push-уведомлений). Вы также сможете сохранять закладки и ставить лайки постам, чтобы выразить свою благодарность другим участникам сообщества.

    С вашими комментариями этот пост мог бы стать ещё лучше 💗

    Зарегистрироваться Войти

    Категории

    • Главная
    • Новости
    • Фронтенд
    • Бекенд
    • Языки программирования

    Контакты

    • Сотрудничество
    • info@exlends.com

    © 2024 - 2026 ExLends, Inc. Все права защищены.

    Политика конфиденциальности
    • Войти

    • Нет учётной записи? Зарегистрироваться

    • Войдите или зарегистрируйтесь для поиска.
    • Первое сообщение
      Последнее сообщение
    0
    • Лента
    • Категории
    • Последние
    • Метки
    • Популярные
    • Пользователи
    • Группы