Symbol 이란
일반적으로 심볼 타입은 객체의 프로퍼티 키를 고유하게 설정함으로써
프로퍼티 키의 충돌을 방지하기 위해 사용된다.
심볼은 Symbol 함수를 호출함으로써 생성할 수 있다.
이때 생성되는 심볼은 변경이 불가능한 원시 값이다.
Symbol 함수를 호출할 때 인자로 전달하는 문자열 값은 생성될 심볼에 대한 일종의 설명문(Description)으로, 오직 디버깅의 용도로만 사용된다.
즉, 뒤에서 설명할 심볼의 키와는 완전히 다른 것으로, console.log() 등을 이용한 디버깅 시에 각 심볼을 구분하기 위한 용도로 사용이 된다.
const sym = Symbol();
const sym2 = Symbol('foo');
const sym3 = Symbol('bar');
console.log(sym); // Symbol()
console.log(sym2); // Symbol(foo)
console.log(sym3); //Symbol(bar)
console.log(typeof sym); // symbol
console.log(typeof sym2); // symbol
console.log(typeof sym3); // symbol
Symbol 함수를 호출하면 매번 새로운(고유한) 심볼이 생성된다. 일치 연산자(===)를 통해 이를 확인해 보자.
const sym1 = Symbol();
const sym2 = Symbol();
const sym3 = Symbol('foo');
const sym4 = Symbol('foo');
console.log(sym1 === sym1); // true
console.log(sym1 === sym2); // false
console.log(sym3 === sym4); // false
그런데 심볼 타입에는 특이한 점이 하나 있다. 그것은 바로 Number, String, Boolean 타입과 달리 new 연산자를 이용한 래퍼 객체의 생성이 불가능하다는 점이다. new 연산자를 이용하여 래퍼 객체를 생성하려고 하면 TypeError가 발생한다. new 연산자를 이용할 수 없다는 것은 곧 Symbol 함수를 생성자로 사용할 수 없음을 의미한다.

심볼도 프로퍼티 키로 사용될 수 있다
const obj = {};
const sym1 = Symbol();
const sym2 = Symbol('foo');
const sym3 = Symbol('foo');
obj[sym1] = 'propertyValue1';
obj[sym2] = 'propertyValue2';
obj[sym3] = 'propertyValue3'; // no conflict with sym2
console.log(obj); // {Symbol(): 'propertyValue1', Symbol(foo): 'propertyValue2', Symbol(foo): 'propertyValue3'}
console.log(obj[sym1]); // propertyValue1
console.log(obj[sym2]); // propertyValue2
console.log(obj[sym3]); // propertyValue3