본문으로 건너뛰기
김신건의 로그

[Javascript] Symbol

· 수정 · 📖 약 1분 · 236자/단어 #javascript #primitive #symbol #fundamentals
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…

이 개념을 다룬 위키 페이지 (1)

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기