JavaScript는 총 6개의 원시 타입(Number, String, Boolean, null, undefined, Symbol)과 1개의 객체 타입(Object)을 가지고 있다. 이번 포스팅에서 다룰 Symbol 타입도 6개의 원시 타입 중 하나로, ES6(ECMAScript 2015)에서 새롭게 추가되었다.
일반적으로 Symbol은 객체의 프로퍼티 키를 고유하게 설정함으로써 키 충돌을 방지하기 위해 사용된다. 다른 타입에 비해 흔하게 사용되는 타입은 아니지만, Symbol에 대한 이해가 전제되어야 이해하고 사용할 수 있는 몇몇 문법(ex. iterable 객체, Well-Known Symbol)들이 있기 때문에 제대로 알아두는 것이 좋다.
MDN 공식 문서에 따르면, Symbol은 고유(unique)하고 변경 불가능한(immutable) 원시 값이다. Symbol() 함수를 호출할 때마다 이전에 생성한 어떤 Symbol과도 같지 않은 완전히 새로운 Symbol 값이 반환된다.
console.log(Symbol() === Symbol()); // false
console.log(Symbol('desc') === Symbol('desc')); // false
console.log(Object.is(Symbol(), Symbol())); // false
마치 세상에 단 하나뿐인 주민등록번호처럼, Symbol은 같은 설명(description)을 넣어도 호출할 때마다 완전히 다른 고유한 값을 만들어낸다. description은 그저 사람이 읽기 위한 디버깅용 라벨일 뿐, Symbol의 고유성에는 아무런 영향을 주지 않는다.
new 키워드는 사용 불가Number, String, Boolean 같은 래퍼 객체처럼 new Symbol()로 생성하려고 하면 TypeError가 발생한다. Symbol은 객체가 아닌 원시 값이기 때문에, 생성자로서 호출하는 것이 의도적으로 막혀 있다.
const sym = new Symbol(); // TypeError: Symbol is not a constructor
Symbol() 함수는 선택적으로 문자열 또는 숫자 형태의 description을 인수로 받는다. 이 description은 Symbol을 식별하는 데 사용되는 사람이 읽기 위한 값이며, .description 프로퍼티로 접근할 수 있다.
const sym1 = Symbol();
const sym2 = Symbol('mySymbol');
const sym3 = Symbol(7);
console.log(sym2.description); // 'mySymbol'
console.log(sym3.description); // '7'
// symbol 타입 확인
console.log(typeof sym1); // 'symbol'
Symbol.for(key)는 일반 Symbol()과 다르게 전역 Symbol 레지스트리에서 주어진 key로 등록된 Symbol을 찾아 반환한다. 없으면 새로 생성하여 등록한다. 이 방식으로 만들어진 Symbol은 key가 같으면 항상 동일한 Symbol을 참조한다. 이에 대해서는 4번 섹션에서 자세히 다룬다.