33장 7번째 데이터 타입 Symbol
1. 심벌이란?
- 변경 불가능한 원시 타입의 값
- 다른 값과 중복되지 않은 유일무이한 값
- 이름의 충돌 위험이 없는 유일한 프로퍼티 키를 만들기 위해 사용
2. 심벌 값의 생성
2.1 Symbol 함수
- 리터럴 표기법 사용 불가능
- 반드시 Symbol 함수를 호출해 생성해야 한다
const mySymbol = Symbol();
console.log(typeof mySymbol);
console.log(mySymbol);
new Symbol();
const mySymbol1 = Symbol('mySymbol');
const mySymbol2 = Symbol('mySymbol');
console.log(mySymbol1 === mySymbol2);
console.log(mySymbol + '');
console.log(+mySymbol);
- 단, boolean으로는 암묵적으로 타입 변환 가능
const mySymbol = Symbol();
console.log(!!mySymbol);
if (mySymbol) console.log('mySymbol is not empty.');
2.2 Symbol.for / Symbol.keyFor 메서드
Symbol.for
- 인수로 전달 받은 문자열을 키로 사용하여 키와 심벌 값의 쌍들이 저장되어 있는 전역 심벌 레지스트리에서 해당 키와 일치하는 심벌 값을 검색
- 검색 성공 시, 검색된 심벌 값을 반환
- 검색에 실패 시, 새로운 심벌 값을 생성하여 Symbol.for 메서드의 인수로 전달된 키로 전역 심벌 레지스트리에 저장한 후, 생성된 심벌 값을 반환
const s1 = Symbol.for('mySymbol');
const s2 = Symbol.for('mySymbol');
console.log(s1 === s2);
Symbol.keyFor
const s1 = Symbol.for('mySymbol');
Symbol.keyFor(s1);
const s2 = Symbol('foo');
Symbol.keyFor(s2);
3. 심벌과 상수
const Direction = {
UP: Symbol('up'),
DOWN: Symbol('down'),
LEFT: Symbol('left'),
RIGHT: Symbol('right')
};
const myDirection = Direction.UP;
if (myDirection === Direction.UP) {
console.log('You are going UP.');
}
4. 심벌과 프로퍼티 키
- 객체의 프로퍼티 키는 빈 문자열을 포함하는 모든 문자열 또는 심벌 값으로 만들 수 있으며 동적으로 생성도 가능
const obj = {
[Symbol.for('mySymbol')]: 1
};
obj[Symbol.for('mySymbol')];
- 위처럼 심벌로 프로퍼티 키를 만들면 다른 프로퍼티 키와 절대 충돌하지 않는다.
5. 심벌과 프로퍼티 은닉
- 심벌은 for ...in 문이나 Object.keys, Object.getOwnPropertyNames 메서드로 찾을 수 없어서 은닉에 유용
const obj = {
[Symbol('mySymbol')]: 1
};
for (const key in obj) {
console.log(key);
}
console.log(Object.keys(obj));
console.log(Object.getOwnPropertyNames(obj));
- ES6부터 Object.getOwnProtpertySymbols 메서드로 찾을 수 있다
const obj = {
[Symbol('mySymbol')]: 1
};
console.log(Object.getOwnPropertySymbols(obj));
const symbolKey1 = Object.getOwnPropertySymbols(obj)[0];
console.log(obj[symbolKey1]);
6. 심벌과 표준 빌트인 객체 확장
- 일반적으로 표준 빌트인 객체에 사용자 정의 메서드를 직접 추가하여 확장하는 것은 권장하지 않음
- 표준 빌트인 객체는 읽기 전용으로 사용하는 것이 좋다
- 왜냐하면, 개발자가 추가한 부분과 미래에 표준 사양으로 추가될 메서드의 이름이 중복될 수 있기 때문이다.
- 이 때 심벌을 이용해 확자앟면 충돌 없이 확장이 가능하다.
Array.prototype.sum = function () {
return this.reduce((acc, cur) => acc + cur, 0);
};
[1,2].sum();
Array.prototype[Symbol.for('sum')] = function () {
return this.redue((acc, cur) => acc + cur, 0);
};
[1,2][Symbol.for('sum')]();
7. Well-known Symbol
function Symbol() { [native code] }
asyncIterator: symbol
for: ƒ for()
hasInstance: symbol
isConcatSpreadable: symbol
iterator: symbol
keyFor: ƒ keyFor()
length: 0
match: symbol
matchAll: symbol
name: "Symbol"
prototype: symbol
replace: symbol
search: symbol
species: symbol
split: symbol
toPrimitive: symbol
toStringTag: symbol
unscopables: symbol
__proto__: ƒ ()
- well-known Symbol : 위처럼 JS가 기본 제공하는 빌트인 심볼
- 이 심볼들은 JS 엔진 내부 알고리즘에 사용된다
- 이를 이용해 일반 객체를 빌트인 객체처럼 사용할 수 있도록 만들 수 있다
const iterable = {
[Symbol.iterator]() {
let cur = 1;
const max = 5;
return {
next() {
return { value: cur++, done: cur > max + 1 };
}
};
}
};
for(const num of iterable) {
console.log(num);
}