Перейти к содержимому

Symbols

В одной фразе: Symbol — уникальный примитив-идентификатор, гарантированно не пересекающийся ни с одним строковым ключом; well-known symbols позволяют “встроиться” в протоколы самого языка. На собесе проверяют знание Symbol.for, Symbol.iterator, Symbol.toPrimitive, Symbol.hasInstance.

// Каждый Symbol() уникален
const s1 = Symbol('id');
const s2 = Symbol('id');
s1 === s2; // false — всегда разные!
// Symbol.for — глобальный реестр по строковому ключу
const g1 = Symbol.for('app.token');
const g2 = Symbol.for('app.token');
g1 === g2; // true — один и тот же из реестра
Symbol.keyFor(g1); // 'app.token'
Symbol.keyFor(s1); // undefined — s1 не из реестра
// Символы как "скрытые" ключи — не видны стандартным итерациям
const _id = Symbol('id');
const user = { name: 'Alice', [_id]: 42 };
Object.keys(user); // ['name'] — symbol не виден
JSON.stringify(user); // '{"name":"Alice"}' — symbol игнорируется
for (const k in user) {} // только 'name'
// Но достать можно:
user[_id]; // 42
Object.getOwnPropertySymbols(user); // [Symbol(id)]
Reflect.ownKeys(user); // ['name', Symbol(id)] — всё
// Well-known Symbol.iterator: делаем объект итерируемым
class Range {
constructor(from, to) { this.from = from; this.to = to; }
[Symbol.iterator]() {
let cur = this.from;
const to = this.to;
return {
next: () => cur <= to
? { value: cur++, done: false }
: { value: undefined, done: true },
[Symbol.iterator]() { return this; } // iterator тоже iterable
};
}
}
[...new Range(1, 5)]; // [1, 2, 3, 4, 5]
Math.max(...new Range(1, 5)); // 5

Итог: Symbols — ключи без риска коллизий. Well-known symbols — это “хуки” для встраивания в протоколы языка (итерация, приведение типов, instanceof и др.).