1. Symbol 이란?
Symbol 은 ES6 에서 추가된 7번째 타입으로,
Symbol 데이터 형식은 값으로 익명의 객체 속성 (Object Property) 을 만들수 있는 특성을 가진 원시 데이터 타입 이다.
클래스나 객체 형식의 내부에서만 접근할수 있도록 전용 객체 속성의 키로 사용된다.
Symbol 은 Symbol 원시 데이터 값 이다.
ES6 이하에는 symbol 과 동등한 형식이 존재하지 않는다.
이 Symbol 은 객체의 속성으로 사용될수 있고, 다른 값과 중복 되지 않는 유일무이한 값이다.
따라서 이름이 충돌할 위험이 없는 객체의 유일한 프로퍼티 키를 만들기 위해 사용한다.
const key = Symbol("key");
log(typeof key); // symbol
let simpleObj = {};
simpleObj[key] = "value";
log(simpleObj["key"]); // value
2. Symbol 함수
JS 런타임 환경에서 Symbol 값은 Symbol() 함수를 호출하여 생성할 수 있는데,
이 함수는 동적으로 익명의 고유한 값을 만들어 낸다.
다른 원시 값은 리터럴로 값을 생성할수 있지만, Symbol 값은 Symbol() 로만 생성할수 있다.
이때 생성된 Symbol 값은 외부로 노출되지 않아 확인이 불가능하고, 다른 값과 중복 되지 않는 유일무이한 값이다.
// Symbol 함수를 호출하여 유일무이한 심볼 값을 생성한다.
const mySymbol = Symbol();
log(typeof mySymbol); // symbol
log(mySymbol); // Symbol()
생성자 함수로 객체를 생성하는 것 처럼 보이지만 Symbol 함수는 다른 String, Number 같은 생성자 함수 와 달리 new 연산자와 함께 호출하지 않는다.
new Symbol(); // Error
new 연산자와 함께 생성자 함수나 클래스를 호출하면 객체 (인스턴스) 가 생성되지만 심벌값은 변경 불가능한 원시 값이다.
그래서 Symbol() 은 불완전한 클래스 이다.
new 와 함께 생성자로 사용할 경우 오류가 발생하는데, 이는 혼동을 유발할 수 있는 의도치 않는 객체의 생성을 막기 위한 예방책 이라 할수 있다.
Symbol 함수에는 Optional 하게 문자열을 인자로 전달할 수 있다.
이 문자열은 생성된 symbol 값에 대한 description 으로 디버깅 용도로만 사용되고, 심볼 값에 어떤 영향도 주지 않는다.
따라서 symbol 값의 description 이 같더라도, 생성된 symbol 은 서로 유일무이한 값이다.
const mySymbol1 = Symbol("mySymbol");
const mySymbol2 = Symbol("mySymbol");
log(mySymbol1 === mySymbol2); // false
symbol 값도 string, number 같이 객체처럼 접근하면 암묵적으로 wrapper 객체를 생성한다.
const mySymbol3 = Symbol("mySymbol");
// description 과 toString 은 Symbol.prototype 의 프로퍼티다.
log(mySymbol3.description); // mySymbol
log(mySymbol3.toString()); // Symbol(mySymbol)
symbol 값은 암묵적으로 문자열이나 숫자 타입으로 변환되지 않는다.
단, boolean 타입으로는 암묵적으로 타입이 변환된다. 이를 통해 if 문 등에서 존재 확인이 가능하다.
const mySymbol4 = Symbol();
// log(mySymbol4 + ""); // Error
// log(+mySymbol); // Error
log(!!mySymbol4); // true
if (mySymbol4) log("mySymbol4 is exist"); // mySymbol4 is exist
3. Symbol.for() / Symbol.keyFor()
전역 심볼 레지스트리에 접근하기 위한 메서드는 Symbol.for() 와 Symbol.keyFor() 이다.
Symbol.for 메서드는 인자로 전달 받은 문자열을 key 로 사용해 key 와 symbol 값의 쌍들이 저장되어 있는 global symbol registry 에서 해당 키와 일치하는 symbol 값을 검색한다.
import { log } from "console";
// mySymbol 이라는 키로 저장된 symbol 이 없으면 새로운 symbol 을 생성
const s1 = Symbol.for("mySymbol");
// mySymbol 이라는 키로 저장된 symbol 이 있으면 해당 symbol 을 반환
const s2 = Symbol.for("mySymbol");
log(s1 === s2); // true
이 메서드들은 global symbol registry 와 runtime 환경 사이를 중재한다.
symbol 레지스트리는 대부분 JS 의 컴파일러 인프라 스트럭쳐에 의해 구축되고, symbol 레지스트리의 컨텐츠는 이러한 메서드들은 통하지 않고서는 JS 의 런타임 인프라 스트럭쳐가 접근할수 없다.
또한 Symbol 함수는 호출될때 마다 유일한 symbol 값을 생성하고, global symbol registry 에서 symbol 값을 검색할 수 있는 키를 지정할 수 없으므로, Symbol() 함수를 통해 생성하면 레지스트리에 등록되어 관리 되지 않는다.
하지만 Symbol.for 를 통해 생성하면 전역에서 공유할수 있게된다.
const s3 = Symbol.for("mySymbol");
// symbol 값의 key 를 추출
log(Symbol.keyFor(s3)); // mySymbol
// 이 경우엔 전역 심볼 레지스트리에 등록되지 않는다.
const s4 = Symbol("foo");
log(Symbol.keyFor(s4)); // undefined
log(Symbol.keyFor(Symbol.for("tokenString")) == "tokenString"); // true
또한 익명의 속성에 할당 할때 식별자 로 사용되며, 비 열거형 이다.
그래서 for ... in 문 내에서 멤버로 사용될수 없고, 속성자체가 익명이기 때문에 Object.getOwnPropertyNames() 가 반환하는 배열에 들어갈수도 없다.
정리하자면,
- Symbol 은 보통 객체의 속성으로 사용되며, 객체의 유일한 프로퍼티 키를 만들기 위해 사용된다.
- Symbol 값은 Symbol() 또는 Symbol.for() 로만 생성할수 있다.
- Symbol.for() 로 생성된 symbol 값만 전역에서 공유된다.
- new 와 함께 Symbol () 을 사용할경우 에러가 발생하며, 의도치 않은 혼란을 막기 위함이라고 볼수 있다.
- Symbol('key') 의 string 값은 key 가 아닌 description 으로만 사용되며,
- Symbol.for('key') 는 'key' 라는 키 값을 가진 symbol 을 생성한다.
- Symbol 은 값이 변환되지 않지만, boolean 값으로는 변환이 된다.
'Javascript' 카테고리의 다른 글
JS에서 제너레이터란 ? (0) | 2022.10.29 |
---|---|
JS 에서의 Symbol 의 사용과 응용 (0) | 2022.09.30 |
reduce 를 이용한 함수 pipe() 를 구현해보자 - JS ES6+ 함수형 프로그래밍 - 19 (0) | 2022.09.28 |
reduce 를 이용한 함수 go() 를 구현해보자 - JS ES6+ 함수형 프로그래밍 - 18 (0) | 2022.09.27 |
map + filter + reduce 중첩 사용과 함수형 사고 - JS ES6+ 함수형 프로그래밍 - 17 (0) | 2022.09.27 |