Для чего нужен тип Symbol в JavaScript?
Что проверяют
Понимаете ли вы, какую задачу решает Symbol: ключ свойства, который гарантированно ни с чем не столкнётся. Следом обычно спрашивают, делает ли символ свойство приватным и что такое well-known символы.
Как отвечать
Symbol это примитивный тип, появившийся в ES2015. Каждый вызов Symbol('id') возвращает новое уникальное значение, описание нужно только для отладки: Symbol('id') !== Symbol('id'). Вызов с new бросает TypeError.
Основные применения:
- ключи без коллизий: библиотека кладёт в чужой объект служебное свойство и не рискует затереть поле пользователя или другой библиотеки;
- свойства вне обычного обхода: символьные ключи не видны в
for...in,Object.keys()иJSON.stringify(). Но это не приватность: их отдаютObject.getOwnPropertySymbols()иReflect.ownKeys(), а spread иObject.assignих копируют; - well-known символы: протоколы языка.
Symbol.iteratorделает объект перебираемым вfor...ofи spread,Symbol.asyncIteratorнужен дляfor await,Symbol.toPrimitiveуправляет приведением к числу и строке,Symbol.toStringTagменяет выводObject.prototype.toString; - глобальный реестр:
Symbol.for('app.key')возвращает один и тот же символ для одного ключа во всём приложении, даже между iframe.Symbol.keyFor()делает обратное.
Пример из фронтенда: React помечает элементы полем $$typeof со значением из Symbol.for. JSON не умеет передавать символы, поэтому подделать React-элемент через данные с сервера нельзя, это защита от одного класса XSS.
Для настоящей приватности в классах сейчас используют поля #private, а не символы.
Где спотыкаются
Называют символы способом сделать свойство приватным. Любой код, у которого есть объект, найдёт его символьные ключи через Reflect.ownKeys().
Пытаются склеить символ со строкой: 'key: ' + sym бросает TypeError. Нужно явно вызвать String(sym) или взять sym.description.
Путают Symbol() и Symbol.for(): ждут, что два Symbol('x') окажутся равны, или не понимают, почему символы из реестра совпадают в разных модулях.