[Javascript] Symbol
JS Symbol, JavaScript Symbol, 심볼
정의
Symbol 은 ES6 도입의 7번째 primitive 타입. 유일성 을 보장하는 식별자.
const s1 = Symbol('description');
const s2 = Symbol('description');
s1 === s2 // false (같은 description 이어도 다름)
typeof s1 // 'symbol'
왜 필요한가
객체의 충돌 없는 키 로 사용. private property 흉내, well-known symbol 로 객체 동작 커스터마이즈.
const KEY = Symbol('myLib_internal');
obj[KEY] = 'data'; // 다른 라이브러리와 충돌 없음
생성
const s = Symbol();
const s = Symbol('foo'); // description (디버깅용)
const s = Symbol.for('shared'); // global symbol registry
Symbol.for
const a = Symbol.for('shared');
const b = Symbol.for('shared');
a === b // true (같은 키)
Symbol.keyFor(a) // 'shared'
Symbol() 은 매번 새 심볼, Symbol.for() 는 같은 키면 같은 심볼.
객체 키로 사용
const id = Symbol('id');
const user = {
name: 'Alice',
[id]: 12345, // computed key
};
user[id] // 12345
user.id // undefined (다른 키)
Object.keys(user) // ['name'] (Symbol 제외)
Object.getOwnPropertySymbols(user) // [Symbol(id)]
심볼 키는 for...in, Object.keys, JSON.stringify 에서 제외. 의도된 hidden property.
Well-known Symbol
엔진이 정의한 특수 심볼. 객체의 내장 동작을 커스터마이즈.
Symbol.iterator // for...of 의 동작
Symbol.asyncIterator // for await...of
Symbol.toPrimitive // 타입 변환
Symbol.toStringTag // Object.prototype.toString
Symbol.hasInstance // instanceof
Symbol.isConcatSpreadable
Symbol.match, Symbol.replace, Symbol.search, Symbol.split // regex
Symbol.species // 파생 객체 생성자
Symbol.iterator
const obj = {
*[Symbol.iterator]() {
yield 1;
yield 2;
yield 3;
}
};
for (const x of obj) console.log(x); // 1, 2, 3
[...obj] // [1, 2, 3]
Symbol.toPrimitive
const obj = {
[Symbol.toPrimitive](hint) {
if (hint === 'number') return 42;
if (hint === 'string') return 'forty-two';
return 'default';
}
};
+obj // 42
`${obj}` // 'forty-two'
obj + '' // 'default'
Symbol.toStringTag
class Foo {
get [Symbol.toStringTag]() { return 'Foo'; }
}
Object.prototype.toString.call(new Foo()) // '[object Foo]'
자주 쓰는 패턴
private property 흉내
const _data = Symbol('data');
class Box {
constructor(x) {
this[_data] = x;
}
get value() { return this[_data]; }
}
진짜 private 은 #private 필드 (ES2022). 심볼은 reflection 으로 접근 가능.
충돌 없는 메서드 추가
const myMethod = Symbol('myMethod');
Array.prototype[myMethod] = function() { return 'custom'; };
[].myMethod // undefined
[][myMethod] // 'custom'
고유 식별자
const STATUS_ACTIVE = Symbol('active');
const STATUS_INACTIVE = Symbol('inactive');
switch (status) {
case STATUS_ACTIVE: ...
case STATUS_INACTIVE: ...
}
문자열 enum 보다 충돌 안전.
함정
1. 자동 변환 없음
const s = Symbol('foo');
String(s) // 'Symbol(foo)' (명시적)
s + '' // ❌ TypeError
`${s}` // ❌ TypeError
심볼은 자동 변환되지 않는다 (실수 방지).
2. JSON 미지원
JSON.stringify({ [Symbol()]: 1 }) // '{}' (심볼 키 제외)
JSON.stringify({ a: Symbol() }) // '{}' (심볼 값 제외)
3. instanceof Symbol
Symbol() instanceof Symbol // false (primitive)
typeof Symbol() === 'symbol' // true
참고
이 글의 용어 (3개)
- [Javascript] 타입 변환 / 강제 변환javascript
- 정의 JavaScript 의 암묵적 형변환 (coercion). 연산자가 양쪽 피연산자의 타입을 자동으로 맞춘다. 명시적 변환과 구분. 3 가지 강제 변환 1. ToString …
- [Javascript] Iterator / Generatorjavascript
- 정의 - Iterator protocol : 메서드가 반환 - Iterable protocol : 가 iterator 반환 - Generator : 으로 정의, yield 로 값…
- [Javascript] Objectjavascript
- 정의 JavaScript 의 는 key-value 쌍의 컬렉션. 거의 모든 non-primitive 값이 객체. 함수, 배열, 정규식도 객체. 생성 접근 수정 / 삭제 Objec…
💬 댓글