Какие ключи могут быть в объекте и в Map в JavaScript
Что проверяют
Знаете ли вы, что у объекта ключ всегда строка или символ, и понимаете ли, к каким багам это приводит. Следом обычно спрашивают, когда вы выберете Map вместо объекта и чем Map отличается от WeakMap.
Как отвечать
Начните с правил приведения ключей:
- объект: ключом может быть только строка или
Symbol. Всё остальное приводится к строке:obj[1]иobj["1"]это одно свойство, а любой объект в роли ключа превращается в"[object Object]", и два разных объекта затирают друг друга; Map: ключом может быть любое значение, включая объекты, функции,NaN,nullиundefined. Сравнение идёт по алгоритму SameValueZero: объекты по ссылке,NaNравенNaN,+0и-0считаются одним ключом;WeakMap: ключом может быть только объект или незарегистрированный символ, ссылка на ключ слабая. Когда объект больше нигде не нужен, запись уходит вместе с ним. ПеребратьWeakMapнельзя.
Дальше про порядок. У объекта он определён стандартом: сначала целочисленные ключи по возрастанию, затем строковые в порядке добавления, затем символы. Символы при этом не попадают в Object.keys и for...in. Map всегда обходится в порядке вставки.
Практические отличия: у Map есть size, он итерируемый и не наследует ключи от прототипа, поэтому ключ "__proto__" или "constructor" из пользовательского ввода ничего не сломает. Объект удобнее для записей с заранее известными полями и для JSON: JSON.stringify(map) вернёт {}, сначала нужен Object.fromEntries(map).
Где спотыкаются
Утверждают, что порядок ключей объекта не гарантирован. Это устаревшее знание: порядок описан в спецификации, просто для числовых ключей он не совпадает с порядком вставки.
Используют объект как словарь с ключами из внешних данных и забывают про прототип. "toString" in obj вернёт true даже для пустого объекта. Спасают Object.create(null), Object.hasOwn или сразу Map.
Ожидают, что map.get({ id: 1 }) найдёт запись, положенную с другим объектом { id: 1 }. Ключи сравниваются по ссылке, поэтому составной ключ собирают в строку, например id + ":" + type, или делают вложенный Map.