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]; // 42Object.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 и др.).