모던 JS Deep dive #33 | 7번째 데이터 타입 Symbol
2022년 09월 30일 16:18
JS의 Symbol 기본
📌 Symbol
1997년 ECMAScript로 표준화된 이래로 JS에는 6개의 타입만 있었다. Symbol은 ES6에서 도입된 7번째 데이터 타입으로 변경 불가능한 원시 타입의 값이다. 심벌 값은 다른 값과 중복되지 않는 유일무이한 값이기 때문에 주로 이름의 충돌 위험이 없는 유일한 프로퍼티 키를 만들기 위해 사용한다.
📌 Symbol의 생성
심벌은 Symbol함수를 통해서 생성하는데 언뜻 보면 String, Number, Boolean생성자 함수처럼 객체를 생성하는 것처럼 보이지만 new 연산자와 함께 호출하지 않는다. 이 Symbol함수에는 선택적으로 문자열을 인수로 전달할 수 있으며 생성된 심벌 값에 대한 설명으로 디버깅 용도로만 사용된다.
const mySymbol1 = Symbol("mySymbol");
const mySymbol2 = Symbol("mySymbol");
console.log(mySymbol1 === mySymbol2);심벌 값도 다른 원시값처럼 객체처럼 접근하면 암묵적으로 래퍼 객체를 생성한다.
mySymbol.description;
mySymbol.toString();📌 Symbol.for & Symbol.keyFor
Symbol.for 메서드는 인수로 전달받은 문자열을 키로 사용하여 키와 심벌 값의 쌍들이 저장되어 있는 global symbol registry에서 해당 키와 일치하는 심벌 값을 검색한다. 일치하는 key가 없다면 만들어서 Symbol을 반환하고, 일치하는 key가 있다면 해당 Symbol을 반환한다.
const s1 = Symbol.for("mySymbol");
const s2 = Symbol.for("mySymbol");
console.log(s1 === s2); //trueSymbol.keyFor 메서드는 global symbol registry에 저장된 심벌 값의 키를 추출할 수 있다. 그냥 Symbol함수를 통해 생성된 심벌은 매칭 키가 없기 때문에 undefined가 반환된다.
Symbol.keyFor(s1); // -> mySymbol
const s3 = Symbol("foo");
Symbol.keyFor(s3); // -> undefinedSymbol의 사용사례
📌 enum만들기
enum은 명명된 숫자 상수의 집합으로 열거형(enumberated type)이라 부른다. 여러 프로그래밍 언어나 typescript는 enum을 지원하지만 JS는 그렇지 않다. enum을 흉내 내어 사용하려면 객체를 동결하는 Object.freeze 메서드와 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) {
//코드 작성
}위와 같이 상수 값 UP, DOWN, LEFT, RIGHT가 변경될 수 없으며, 다른 변수 값과 중복될 수 없도록 코드를 작성하면 된다.
📌 객체의 유일무이한 키 만들기
객체의 프로퍼티 키는 빈 문자열을 포함하는 모든 문자열이나 심벌 값으로 만들 수 있기 때문에 아래와 같이 유일무이한 키를 만들 수 있다. (프로퍼티 키 동적 생성에 대해서는 10장에서 알아 봤다.)
const obj = {
[Symbol.for("mySymbol")]: 1,
};
obj[Symbol.for("mySymbol")]; // -> 1📌 표준 빌트인 객체 확장
일반적으로 표준 빌트인 객체에 사용자 정의 메서드를 직접 추가해서 확장하는 것은 비추며, 읽기 전용으로만 사용하는 것이 좋다. 그 이유는 개발자가 직접 추가한 메서드와 미래에 표준 사양으로 추가될 메서드의 이름이 중복될 수 있기 때문이다.
하지만 중복 가능성이 없는 심벌 값으로 프로퍼티 키를 생성하여 표준 빌트인 객체를 확장하면 그런 문제가 해결이 된다.
Array.prototype[Symbol.for("sum")] = function() {
return this.reduce((acc, cur) => acc + cur, 0);
}[(1, 2)][Symbol.for("sum")](); // -> 3;Symbol 고난이도
📌 Symbol의 애매한 프로퍼티 은닉
아래처럼 심벌 값을 프로퍼티 키로 사용하여 프로퍼티를 생성하면 외부에 노출할 필요가 없는 프로퍼티를 은닉할 수 있다.
const obj = {
[Symbol("mySymbol")]: 1,
};
console.log(Object.keys(obj)); // []
console.log(Object.getOwnPropertyName(obj)); // []하지만 ES6에서 도입된 Object.getOwnPropertySymbols 메서드를 통해 심벌 값을 프로퍼티 키로 사용해 생성한 프로퍼티를 찾을 수 있다.
const symbolKey1 = Object.getOwnPropertySymbols(obj)[0];
console.log(obj[symbolKey1]); //1즉, 프로퍼티를 완전히 숨길 수 있는 건 아니다.
📌 Well-known Symbol
=> 도저히 이해가 안되는데 강해져서 돌아오자 (22.09.30)