7번째 데이터 타입 Symbol
1997년 JS 가 ECMAScript 로 표준화 된 이래로 JS 에는 6개의 타입
문자열, 숫자, 불리언, undefined, null, 객체 타입이 있었다.
Symbol 은 ES6에 도입된 7번째 데이터 타입으로 변경 불가능한 원시 타입이다.
다른 값과 중복되지 않는 유일무이한 값을 가지기 때문에, 충돌하면 안되는 프로퍼티 키 값으로 많이 사용된다.
프로퍼티 키로 사용할 수 있는 값은 빈 문자열, 문자열, 심벌 값이다.
값 만드는 방법
const s = Symbol();
console.log(typeof s); // symbol언뜻 보면 생성자 함수로 객체를 생성하는 것 같지만 new 연산자와 함께 호출하지 않는다.
Symbol 함수에 선택적으로 문자열을 인수로 전달 가능한데, 이 문자열은 단순한 설명 용도이다.
const s1 = Symbol('설명1') // s1.description
const s2 = Symbol('설명2')
console.log(s1 === s2); // false객체 처럼 접근하면 암묵적으로 래퍼 객체를 생성해서 사용한다.
암묵적 타입 변환은 불리언 타입만 작동한다. 이를 통해 if 문 등에서 존재 확인가능하다.
console.log(!!symbol) // true
전역 심벌 레지스트리
키와 심벌 값의 쌍들이 저장되어 있는 global symbol registry 가 있다.
Symbol.for 메서드는 인수로 전달받은 문자열을 키로 사용하여 전역 심벌 레지스트리에서 해당 키와 일치하는 심벌 값을 검색한다.
const s1 = Symbol.for('hayashi') // 인수를 키로 갖는 심벌 값 저장
const s2 = Symbol.for('hayashi') // 이미 있기 때문에 심벌 값 반환
console.log(s1 === s2) // true;Symbol 함수를 호출하여 생성한 심벌 값은 전역 심벌 레지스트리에 등록되어 관리되지 않는다.
const s = Symbol('doo')
Symbol.keyFor('doo') // undefined예제
상수
왼쪽의 경우에는 상수 값 1,2,3,4 가 변경될 수 있으며, 다른 변수 값과 중복될 수도 있다.
const Direction = {
UP: 1,
DOWN: 2,
LEFT: 3,
RIGHT: 4
};
const d = Direction.UP;
if (d === Direction.UP) console.log("UP");const Direction = Object.freeze({
UP: Symbol('up'),
DOWN: Symbol('down'),
LEFT: Symbol('left'),
RIGHT: Symbol('right')
});
const d = Direction.UP;
if (d === Direction.UP) console.log("UP");오른쪽의 경우에는 객체의 변경을 방지하기 위한 Object.freeze.
심벌 값으로 중복될 가능성을 제거하였다.
프로퍼티 키
다른 프로터피 키와 절대 충돌하지 않는 유일무이한 키를 만든다.
const obj = {
[Symbol.for('me')]: 1
}
obj[Symbol.for('me')]; // 1심벌 값을 프로퍼티 키로 사용하면 for...in 문이나 Object.keys, Object.getOwnPropertyNames 메서드로 찾을 수 없다.
어느 정도 은닉을 가능하게 하지만, ES6 에 추가된 Object.getOwnPropertySymbols 메서도를 통해 찾을 수 있다.
표준 빌트인 객체 확장
Array.property.sum = function () {
return this.reduce((acc, cur) => acc + cur, 0);
};
[1, 2].sum(); // 3위와 같이 표준 빌트인 객체에 사용자 정의 메서드를 직접 추가했다고 해보자.
일반적으로 좋지 않은데, 나중에 새롭게 도입된 메서드의 이름이 sum 일 경우에 해당 메서드를 사용자 메서드가 덮어쓰기 때문이다.
하지만 여기서 심벌 값으로 프로퍼티 키를 생성하여, 표준 빌트인 객체를 확장한다면, 그런 문제가 없다.
Array.property[Symbol.for('sum')] = function () {
return this.reduce((acc, cur) => acc + cur, 0);
};
[1, 2][Symbol.for('sum')](); // 3Well-known Symbol
JS 에서 기본 제공하는 심벌 값들은 Symbol 함수의 프로퍼티에 할당되어 있다.
그중 하나인 Symbol.iterator 는 for...of 문으로 순회 가능한 빌트인 이터러블이 키로 가지고 있다.
Symbol.iterator 메서드를 호출하면 이터레이터를 반환하도록 ECMAScript 사양에 규정되어 있다.
이 규정, 이터레이션 프로토콜을 준수하면, 빌트인 이터러블이 아닌 일반 객체를 이터러블처럼 동작하도록 구현할 수 있다.
const normalObj = {
[Symbol.iterator]() {
let cur = 1;
const max = 5;
return {
next() {
return { value: cur++, done: cur > max + 1 };
}
};
}
};
for (const num of normalObj) {
console.log(num) // 1 2 3 4 5
}정리
심벌은 중복되지 않는 상수 값을 생성하는 것은 물론 기존에 작성된 코드에 영향을 주지 않고 새로운 프로퍼티를 추가하기 위해,
즉 하위 호환성을 보장하기 위해 도입되었다.