ES6 Symbol 오브젝트
Comment
Symbol에 대해서 이해가 안갔는데 C언어의 enum과 비슷한 개념이라고 설명한 부분에서 살짝 감이 왔다.
ECMAScript6 책 (두고두고 보는 자바스크립트 표준 레퍼런스) 인프런 JavaScript ES6+ 제대로 알아보기 – 중급 :: symbol
심볼은 3가지 형태로 사용할 수 있다.
- Symbol(): Symbol 값을 생성하며 스코프 안에서 사용한다.
- Symbol.for(): 글로벌 Symbol registry에 저장되며 전체 프로그램에서 사용한다.
- Well-Known Symbol: 빌트인 Symbol 프로퍼티로 오버라이드하여 기능을 추가, 변경할 수 있다.
1. primitive string, number, boolean은 레퍼(Wrapper) 오브젝트가 있다. - string은 String -
number는 Number - boolean은 Boolean - es6에서 symbol의 Symbol 오브젝트가 추가되었다.
wrapper 오브젝트는 vlaueOf()로 프리미티브 값을 구할 수 있지만, symbol은 값을 반환하지 않는다.
2. Symbol() Symbol([description]) - description: 설명, 주석 - 반환값: 유니크한 Symbol 값
let sym = Symbol();- new 연산자를 사용하지 않는다.
- Symbol()로 생성된 값은 프로그램 전체를 통해 유일하고, 값을 변경할 수 없다.(immutable)
- C언어의 enum과 비슷한 개념이다.
- 생성한 Symobol에 프로퍼티를 설정할 수 없다.
- 반환자가 오브젝트가 아니므로, 오브젝트를 생성한다고 할 수 없다.
- symbol값을 생성한다는 표현이 적절하다.
- String의
'', Array의[]처럼 Symbol을 생성하는 리터럴이 없다.
- undefined와 null 처럼 그 자체가 값이 되는 것도 아니다.
- 함수로 호출해야 값을 생성하여 반환한다.
Symbol()
- Symbol()로 값을 생성하고 출력하면, Symbol()로 생성한 값을 반환하지 않고, Symbol 값을 생성했던
형태를 반환한다.이는 symbol의 특징이다. - Symbol값을 외부에 노출시키지 않는 것이 Symbol의 특징이다.
- Symbol()로 생성한 값의 설명이나 주석을 문자열로 작성한다. Symbol값을 외부에 제공하지 않으므로
디버깅할 때 유용하다. 파라미터를 작성하지 않으면
undefined로 인식한다.
feature1: const sym = Symbol();
feature6: sym // Symbol()
feature_: typeof sym // symbol
feature8: Symbol("주석") // Symbole(주석)
feature2: sym == Symbole() // false3. Symbol 값 변경 - Symbol()로 생성한 Symbol값은 변경할 수 없다. - Symbol값에 문자열을 추가하고
싶을 경우 Symbol을 toString()이나 String()으로 변환한 후 연결해야한다.
4. Symbol 오브젝트 생성 Object(123)처럼 Object()의 파라미터에 123을 지정하면 Number 오브젝트를
반환한다. - Object() 파라미터에 Symbol 값을 지정하면 Symbol 오브젝트를 반환한다. - Symbol 오브젝트에 Symbol메서드, Symbol.prototype, protototype에 연결된 프로퍼티가 설정된다.
5. 오브젝트에서 Symbol 사용 유일한 값을 갖는 Symbol 특성을 활용하여 Symbol 값을 오브젝트의
프로퍼티 키로 사용하면 프로퍼티 키가 중복되지 않습니다.
symbol-keyed property
[Symbol()]형태와 같이 대괄호 안에 Symbol()을 작성
{[Symbol()]: 123}이렇게 프로퍼티 키에 작성한 Symbol()을 **symbol-keyed property**라고 한다.
{'{'} ABC : 123 {'}'}에서ABC에 Symbol값을 넣은 것이다. 여기서 Symbol값은 문자열이 아니라 그냥 Symbol값이라고 생각하면된다.
let sym = Symbol('123');
let obj = { [sym]: '456' };
console.log(obj); // {Symbol(123): "456"}
console.log(obj[sym]); // 456
console.log(obj.sym); // undefined대괄호를 사용하지 않고 obj.sym 형태로 작성하면 에러는 안나지만 undefined가 반환된다.
- Symbol을 키로 갖는 프로퍼티를
<<>>형태로 표기하고 있다.
6. Symbol 사용형태 for-in 문에서 symbol-keyed property는 열거되지 않는다. - Symbol이
[[Enumerable]]: false이기 때문. (객체의 데이터 프로퍼티에서 [[Enumerable]]은 기본적으로
true이다.)
6.1 for-in 문에서 Symbol 사용 (외부스코프에서 의미없는 키값 => symbol화)
let obj = { nine: 999 };
obj[Symbol('one')] = 111;
obj[Symbol('two')] = '222';
console.log(obj);
for (const key in obj) {
console.log(key);
}
// {nine: 999, Symbol(one): 111, Symbol(two): "222"}
// nine일반적으로 for-in문으로 객체를 순회하면서 symbol-keyd property는 접근할 수 없다. 때문에 객체의 고유한 식별자로써, 상수개념으로 사용한다. 외부 스코프에서 의미가 있지 않는 값들만 symbol화 시킨다. 은닉화의 목적이 있기때문에 외부 스코프에서는 접근가능하지 않아야하지만 내부에서는 가능하도록 만들어야한다.
Object.getOwnPropertySymbols()를 사용하여 symbol-keyed property 키값들을 열거할 수 있다.Reflect.ownKeys를 사용하면 symbol-keyed property 키와 값까지 알 수 있다.
6.2 클래스 메서드 이름으로 Symbol 사용
const symbolOne = Symbol('symbol one');
const symbolTwo = Symbol('symbol two');
class Sports {
static [symbolOne]() {
return 'Symbol-1';
}
[symbolTwo]() {
return 'Symbol-2';
}
}
console.log(Sports[symbolOne]());
const obj = new Sports();
console.log(obj[symbolTwo]());6.3 JSON.stringify()에서 Symbol 사용
let sym = Symbol('key');
let result = JSON.stringify({ [sym]: '값' });
console.log(result); // {}빈 오브젝트가 반환된다. 이는 Symbol 값을 외부에 노출되지 않도록 하기 위한 조치이다.
6.4 프로퍼티 은닉화 - symbol로 정의된 키값에는 바로 접근이 불가능하다. - 키값이 들어있는
프로퍼티를 객체 내부에 적용해놓으면 심볼 키에 접근가능하다.
const x = () => {
const a = Symbol('a');
return {
[a]: 10,
a: a,
};
};7. Symbol.for
public member 전역공간에서 공유되는 심볼. 여기저기서 많이 사용되는 공용상수를 사용할때 사용
const a = Symbol.for('abc');
// 새로 생성해서 넣음.
console.log(a); // "Symbol(abc)"
const b = Symbol.for('abc');
// 기존에 'abc' 식별자로 되어있는 symbol을 찾아서 있으면 넣어준다.
console.log(b); // "Symbol(abc)"
a === b; // true?! a와 b가 값과 타입이 같다고 나온다. Symbol.for는 for의 인자를 식별자로 사용한다.
const obj1 = (() => {
const COMMON1 = Symbol.for('공유심볼');
return {
[COMMON1]: '공유할 프로퍼티 키값. 어디서든 접근 가능',
};
})();
obj1[Symbol.for('공유심볼')];
// "공유할 프로퍼티 키값. 어디서든 접근 가능"