🔮 Symbol
- 자바스크립트의 ES6에서 도입된 7번째 데이터 타입
- 변경 불가능한 원시값, 다른 값과 중복되지 않는 유일무이한 값
✨ 생성 -> Symbol 함수
- 심벌값은 Symbol 함수를 호출하여 생성해야 한다.
- 생성된 심벌 값은 외부로 노출되지 않아 확인할 수 없고, 다른 값과 절대 중복되지 않는다.
const firstSymbol = Symbol();
console.log(typeof firstSymbol); // symbol
- 생성자 함수로 객체를 생성하는 것처럼 보이지만, 생성자 함수들과 달리 new 연산자와 함께 호출하지 않는다.
new 연산자로 생성된 것들을 호출하면 객체(인스턴스)가 생성되지만, 심벌 값은 변경 불가능한 원시값이다.
- 심벌 함수에는 선택적으로 문자열을 인수로 전달할 수 있다.
- 생성된 심벌 값에 대한 설명으로 디버깅용도로만 사용되며, 심벌 값 생성에 어떠한 영향을 주지 않는다.
- 심벌 값에 대한 설명이 같더라도 심벌 값은 유일무이하게 생성된다.
const f_symbol1 = Symbol('first Symbol');
const f_symbol2 = Symbol('first Symbol');
console.log(f_symbol1 === f_symbol2) // false
- 심벌 값은 암묵적으로 문자열이나 숫자 타입으로 변환 되지 않는다.
- 단, 불리언 타입으로는 암묵적으로 타입 변환된다.
const mySymbol = Symbol();
// 문자열, 숫자 타입으로 변환되지 않는다.
// Uncaught TypeError: Cannot convert a Symbol value to a string ...
console.log(mySymbol + '');
console.log(+mySymbol);
// 불리언 타입으로는 변환된다.
console.log(!!mySymbol); // true
// if문 등에서 존재 확인 가능하다.
if(mySymbol)
console.log('mySymbol is not empty');
- Symbol 함수는 호출될 때마다 유일무이한 심벌 값을 생성한다.
- 이때 전역 심벌 레지스트리에서 심벌 값을 검색할 수 있는 키를 지정할 수 없으므로 전역 심벌 레지스트리에 등록되어 관리되지 않는다.
- 하지만, Symbol.for 메서드 사용하여 값을 생성하면 전역 심벌 레지스트리 통해 공유할 수 있다.
🙋♀️ 전역 심벌 레지스트리?
- 자바스크립트 엔진이 관리하는 심벌 값 저장소
🕵️ Symbol.for()
- 검색에 성공하면 새로운 심벌 값을 생성하지 않고 검색된 심벌 값을 반환한다.
- 실패하면 새로운 심벌 값을 생성하여 Symbol.for 메서드의 인수로 전달된 키로 전역 심벌 레지스트리에 저장 후, 생성된 심벌 값 반환한다.
// 검색에 실패,
// 새로운 심벌 값을 생성하여 Symbol.for 메서드의 인수로 전달된 키로 전역 심벌 레지스트리에 저장 후
// , 생성된 심벌 값 반환한다.
const s1 = Symbol.for('mySymbol');
// 검색에 성공,
// 해당 심벌 값을 반환한다.
const s2 = Symbol.for('mySymbol');
console.log(s1 === s2); // true
🕵️ Symbol.keyFor()
- 전역 심벌 레지스트리에 저장된 심벌 값의 키를 추출할 수 있다.
// 전역 심벌 레지스트리에 mySymbol이라는 key로 저장된 심벌 값이 없으면 새로운 심벌 값을 생성 후 반환한다.
const s1 = Symbol.for('mySymbol');
// 키를 추출할 수 있다.
Symbol.keyFor(s1); // mySymbol
// Symbol 함수를 호출하여 생성한 심벌 값은 전역 심벌 레지스트리에 등록되어 관리되지 않기 때문에
const s2 = Symbol('foo');
// 키를 추출 했을때 undefined 값이 호출된다.
Symbol.keyFor(s2); // undefined
🔒 심벌과 상수
- 값에는 특별한 의미가 없고 상수 이름 자체에 의미가 있는 경우
- 상수 값은 변경될 수 있으며, 다른 변수 값과 중복될 수도 있다.
- 이러한 경우 중복될 가능성이 없는 심벌 값을 사용한다.
const Direction = {
UP: Symbol('up'),
DOWN: Symbol('down'),
LEFT: Symbol('left'),
RIGHT: Symbol('right')
};
const myDirection = Direction.UP;
if(myDirection === Direction.UP) {
console.log('GOING UP')
}
// GOING UP
🔑 심벌과 프로퍼티 키
- 심벌 값을 프로퍼티 키로 사용하려면 프로퍼티 키로 사용할 심벌 값에 대괄호를 사용해야 한다.
- 접근할 때도 대괄호를 사용해야 한다.
- 심벌 값으로 프로퍼티 키를 만들면 다른 프로퍼티 키와 절대 충돌하지 않는다.
const obj = {
// 생성
[Symbol.for('mySymbol')]: 1
};
obj[Symbol.for('mySymbol')]; // 1
🪄 심벌과 프로퍼티 은닉
- 심벌 값을 프로퍼티 키로 사용하여 생성한 프로퍼티는 for ...in, Object.keys, Object.getOwnPropertyNames 메서드로 찾을 수 없다.
-> 심벌 값을 프로퍼티 키로 사용하여 프로퍼티 생성 시 외부에 노출할 필요가 없는 프로퍼티를 은닉할 수 있다.
- 하지만, 완전하게 숨길 수 있는 것은 아니고 ES6에서 도입된 Object.getOwnPropertySymbols 메서드 사용하면 찾을 수 있다.
const obj = {
[Symbol('mySymbol')]: 1
};
// getOwnPropertySymbols 메서드는 인수로 전달한 객체의 심벌 프로퍼티 키를 배열로 반환한다.
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(mySymbol)]
// getOwnPropertySymbols 메서드로 심벌의 값도 찾을 수 있다.
const symbolKey1 = Object.getOwnPropertySymbols(obj)[0];
console.log(obj[symbolKey1]); // 1
참조 문헌: 모던자바스크립트 Deep dive, 이웅모 저, pp.605 ~ 613