심벌(Symbol)은 ES6에서 도입된 7번째 타입으로 변경이 불가능한 원시값이다.
심벌은 다른 값과 중복되지 않는 특징이 있어 주로 객체의 프로퍼티 키를 만드는데 사용되며
이름 충돌의 위험을 없앨 수 있다.
이름 충돌 예시
const obj = {
key: 'value1',
};
// 누군가 같은 이름의 키를 추가
obj.key = 'value2';
console.log(obj.key); // 'value2' - 기존 값이 덮어쓰여짐
객체에서 프로퍼티 키로 문자열을 사용할 때, 같은 이름의 키가 추가되면 기존 값이 덮어쓰여질 수 있는
문제가 생길 수 있다.
심벌 값은 Symbol 함수를 호출하여 생성할 수 있다.
그리고 생성한 심벌 값은 외부로 노출되지 않아 확인할 수 없다.
const mySymbol = Symbol();
console.log(typeof mySymbol); // symbol
console.log(mySymbol); // Symbol()
mySymbol을 호출하면 Symbol() 형식으로 보이지만, 그 뒤에 실제 심볼의 고유 값은 표시되지 않는다.
즉, Symbol()은 심볼의 고유 값을 확인할 수 없는 방식으로 출력되는 것이다.
Symbol 함수는 new 연산자와 함께 호출하여 객체(인스턴스)를 만들수 없다.
즉, new 연산자와 호출할 경우 타입에러가 발생한다.
왜냐하면 Symbol은 생성자 함수가 아니고 그저 원시 타입을 생성하는 함수로 사용되기 때문이다.
const mySymbol = new Symbol();
console.log(mySymbol); // TypeError: Symbol is not a constructor
Symbol 함수의 인자에는 문자열을 전달할 수 있다.
문자열은 함수에 대한 설명일 뿐, 심볼의 고유값을 변경하거나 심볼 자체의 동작에 영향을 미치지 않는다.
const mySymbol = Symbol("hello");
const mySymbol2 = Symbol("hello");
console.log(mySymbol === mySymbol2); // false
설명의 역할
1. 디버깅: 개발 중에 심벌을 출력하거나 로그에 찍을 때, 그 심벌이 무엇을 나타내는지 알 수 있도록 돕는다. 예를 들어, 심벌의 설명을 통해 해당 심벌이 어떤 기능을 위한 것인지 확인할 수 있다.
2. 디버깅을 위한 문자열: 심벌을 로그에 출력할 때 설명이 표시되므로, 코드에서 심벌을 추적할 때 도움이 된다.
const sym = Symbol("uniqueKey");
console.log(sym); // Symbol(uniqueKey)
console.log(sym.description); // "uniqueKey"
심벌 값도 객체처럼 접근시 암묵적으로 래퍼 객체를 생성한다.
const mySymbol = Symbol("hello");
console.log(mySymbol.description); // hello
console.log(mySymbol.toString()); // Symbol(hello)
심벌 값은 숫자타입이나 문자타입으로 암묵적으로 타입 변환되지 않는다.
그러나 불리언 타입으로는 암묵적으로 타입 변환된다.
const mySymbol = Symbol("hello");
console.log(mySymbol + 1); // error
console.log(mySymbol + " "); // error
console.log(!!mySymbol); // true
const sym1 = Symbol.for("shared");
const sym2 = Symbol.for("shared");
const sym3 = Symbol("shared")
console.log(sym1 === sym2); // true(같은 심볼을 반환)
console.log(sym1 === sym3); // false(서로 다른 심볼)
🚀 전역 심벌 레지스트리
전역 심볼 레지스트리는 심볼 값을 전역적으로 관리하기 위한 저장소
일반적으로 Symbol()로 생성한 심볼은 고유하지만, 전역 심볼 레지스트리를 통해 특정 키를 가진 심볼을 공유할 수 있다.
둘다 유일무이한 심벌 값을 생성하지만 Symbol 함수는 전역 심벌 레지스트리에 키를 지정할 수 없기 때문에 전역 심벌 레지스트리에서 등록돼 관리되지 않는다.
반면에 Symbol.for 메서드는 고유한 심벌이 전역 심벌 레지스트리에 등록되어 같은 심볼 값을 공유할 수 있다.
전역 심벌 레지스트리에 등록된 심벌 값의 키를 추출 할 수 있다.
const mySymbol = Symbol.for("hello");
console.log(Symbol.keyFor(mySymbol)); // hello
const mySymbol2 = Symbol("hello");
console.log(mySymbol2.keyFor("hello")); // error
JS는 enum을 지원하지 않지만 Symbol을 활용하면 enum과 같은 역할을 하는 코드를 짤 수 있다.
enum
열거형이라 불리며, 미리 정의된 상수들의 집합을 나타내는 데이터 구조.
C,파이썬,JAVA등의 언어와 TS에서 지원한다.
Symbol을 enum의 값을 유일하게 보장하는 방식으로 활용할 수 있다.
TS의 enum
enum Direction {
UP = "up",
DOWN = "down",
LEFT = "left",
RIGHT = "right",
}
const myDirection: Direction = Direction.UP;
if (myDirection === Direction.UP) {
console.log("you go to up");
}
Symbol을 사용하여 만든 열거형 집합
const Direction = Object.freeze({
UP: Symbol("up"),
DOWN: Symbol("down"),
LEFT: Symbol("left"),
RIGHT: Symbol("right"),
});
const myDirection = Direction.UP;
if (myDirection === Direction.UP) {
console.log("you go to up");
}
Direction 객체를 변경 불가능하게만들었고 Symbol을 이용해 상수 값들을 고유한 값으로 만들었다.
이런식으로 enum과 같이 상수 값을 안전하게 관리할 수 있다.
객체의 프로퍼티 키는 모든 문자열 또는 심벌 값으로 만들 수 있다.
심벌 값을 프로퍼티 키로 사용하는 방법은 심벌 값에 대괄호를 붙여주면 된다.
또한 프로퍼티에 접근할 때도 대괄호를 붙여줘야한다.
const obj = {
[Symbol.for("mySymbol")]: 1,
};
console.log(obj[Symbol.for("mySymbol")]); // 1
심벌 값은 유일무이한 값이기 때문에 다른 프로퍼티 키와 절대 충돌하지 않는다.
심벌 값을 프로퍼티 키로 사용해 생성한 프로퍼티는 for...in, Object.keys, Object.getOwnPropertyNames 메서드로 찾지 못한다.
즉 외부에 노출되지 않고 은닉된다.
왜냐하면 Symbol은 고유한 값을 가지기 때문에 기본적으로 열거되지 않는다.
(자바스크립트의 설계에 따른 특성)
const mySymbol = Symbol('mySymbol');
const obj = {
[mySymbol]: 'This is a symbol value',
regular: 'This is a regular value',
};
for (let key in obj) {
console.log(key); // regular
}
그러나 Object.getOwnpropertySymbols 메서드를 사용하면 객체에서
심벌 프로퍼티만 배열로 반환할 수 있다.
console.log(Object.getOwnPropertySymbols(obj)); // [ Symbol(mySymbol) ]
자바스크립트에서 미리 정의한 특별한 심볼 값이 있다. 이를 빌트인 심벌이라고 한다.
빌트인 심벌 값들은 Symbol 함수의 프로퍼티에 기본적으로 할당되어 있다.

그리고 빌트인 심벌을 ECMAScrit 사양에서는 Well-known Symbol이라고 부르며
자바스크립트 엔진 내부 알고리즘에 사용된다.
대표적으로 Symbol.iterator가 있다.
Array,String,Map,Set,arguments,HTMLCollection,NodeList 같은 이터러블은 for...of문으로 순회 가능하다.
왜냐하면 이들은 Well-known Symbol인 Symbol.iterator를 키로 갖는 메서드를 가지기 때문이다.
Symbol.iterator 메서드를 호출하면 이터레이터를 반환하도록 ECMAScript 사양에 규정되어있다.
빌트인 이터러블은 이러한 규정, 이터레이션 프로토콜을 준수한다.
이 내용은 Iterator 파트에서 추가적으로 다루겠다.
핵심
즉, 이터레이션 프로토콜을 준수하기 위해 일반 객체에 존재해야하는 메서드의 키 Symbol.iterator는 고유한 값을 가져 다른 프로퍼티 키와 절대 중복되지 않는다는 것이다.
또한 Symbol.iterator를 키를 갖는 메서드가 이터레이션 프로토콜을 준수한다면
순회가 가능하다는 것이다.