Символы
Символ (symbol) — особый примитивный тип данных: значение, которое гарантированно уникально. Символы используют как ключи свойств, которые не должны случайно совпасть с другими ключами или попасть в обычный перебор. Сам JavaScript с их помощью описывает поведение объектов, например перебор в for...of.
Создание символа
Символ создают функцией Symbol(). Каждый вызов даёт новое значение, не равное никакому другому — даже символу с тем же описанием:
console.log(Symbol('id') === Symbol('id')); // falseОписание символа
Строка в скобках — описание символа. Оно нужно только для отладки: помогает понять, что это за символ, при выводе в консоль:
const id = Symbol('id');
console.log(typeof id); // symbol
console.log(id.description); // idСимвол как ключ
Символ можно сделать ключом свойства объекта. При создании объекта его пишут в квадратных скобках, обращаются к свойству тоже через скобки:
const id = Symbol('id');
const user = { name: 'Анна', [id]: 7 };
console.log(user[id]); // 7Добраться до такого свойства может только тот, у кого есть сам символ. Посторонний код не перезапишет его по ошибке, даже если заведёт своё свойство id.
Скрытые свойства
Свойства-символы не попадают в Object.keys(), цикл for...in и JSON.stringify(). Поэтому в них удобно хранить служебные данные, которые не должны уйти на сервер:
const id = Symbol('id');
const user = { name: 'Анна', [id]: 7 };
console.log(Object.keys(user).join(', ')); // name
console.log(JSON.stringify(user)); // {"name":"Анна"}Полностью они не спрятаны: Object.getOwnPropertySymbols(user) вернёт их список.
Глобальный реестр: Symbol.for
Иногда разным частям программы нужен один и тот же символ. Symbol.for() ищет символ с таким именем в общем реестре и создаёт его, только если его там ещё нет:
const a = Symbol.for('app.id');
const b = Symbol.for('app.id');
console.log(a === b); // trueВстроенные символы
У JavaScript есть набор встроенных символов, через которые объект настраивает своё поведение. Symbol.iterator из прошлого урока делает объект перебираемым, а Symbol.toPrimitive решает, во что объект превратится в вычислениях:
const price = {
amount: 12,
[Symbol.toPrimitive]() {
return this.amount;
},
};
console.log(price * 2); // 24Частая ошибка
Обращаться к свойству-символу через точку. Запись user.id ищет обычное свойство со строковым ключом 'id', а не символ из переменной id:
const id = Symbol('id');
const user = { [id]: 7 };
console.log(user.id); // undefined
console.log(user[id]); // 7