[JS] #12 Symbol 오브젝트
primitive 값
Primitive값은 오브젝트가 아니라 값이며 함수를 가지고 있지도 않습니다. 예를 들어 const num = 100; 을 실행하면 num이라는 변수에는 100만 할당되며 그 외 아무것도 첨부되지 않습니다. 100이 num의 primitive값 입니다.
ES5에서는 primitive 값 타입이 string, number, boolean, null, undefined이 있습니다. ES6에서 symbol 타입이 추가되었습니다.
wrapper 오브젝트
wrapper 오브젝트란 Primitive값이 포함된 오브젝트로 Primitive값과는 다르게 메소드가 있습니다.
- wrapper 오브젝트가 있는 프리미티브 값 타입
- string: String
- number: Number
- boolean: Boolean
- symbol: Symbol - 외부에 노출되지 않는 특성
- undefined, null은 wrapper 오브젝트가 없기 때문에 값으로만 사용할 수 있습니다.
const stringObj = new String(100); const stringValue = 200; const numberObj = new Number(123); const numberValue = 456; const sym = Symbol("ABC");
- 빌트인 오브젝트로 설정할 때는 만들어진 인스턴스의 [[PrimitiveValue]]에 설정됩니다.
- numberObj, stringObj가 wrapper 오브젝트입니다.
- sym은 펼칠 수가 없으며, [[PrimitiveValue]]가 표시되지 않습니다.
- 하지만, 실제로 Primitive값이 없는 것은 아니며 외부에 노출시키지 않는 특성 때문입니다.
- Symbol 오브젝트는 new 연산자로 인스턴스를 만드는 것도 이러한 특성에 의해서 불가능합니다.
Symbol() 함수
Symbol()은 값을 생성하여 반환하는데, 반환된 값은 노출되지 않아 확인할 수 없습니다. 다른 값에 중복되지 않는 유일무이한 값으로 따라서, 주로 충돌 위험이 없는 유일한 프로퍼티 키를 만들기 위해 사용합니다.
const sym = Symbol(); console.log(sym); console.log(typeof sym); // Symbol() // symbol
새로운 값을 생성해 반환하기 때문에 값을 설정하기보다는 생성한다는 표현이 적절합니다. Symbol 값이 출력되지 않고, 생성한 코드 형태가 표시됩니다. 이는 생성한 값을 외부에 노출시키지 않으려는 의도로 볼 수 있습니다.
const one = Symbol("mySymbol"); const two = Symbol("mySymbol"); console.log(one === two); // false
둘 다 출력을 해보면 Symbol(mySymbol)을 출력하지만 실제로는 프로그램 전체에서 하나만 있는 값을 생성하기 때문에 둘을 비교하면 false가 출력됩니다.
이렇게 외부노출에 폐쇄적이라는 말은 Symbol 값으로 연산을 하거나 타입을 변경하는것도 불가능하다는 말이 됩니다.
-
Symbol 값으로 연산불가
let sym = Symbol(); try { const add = sym + 5; } catch(e) { console.log("연산 불가"); }; // 연산 불가
-
Symbol 값 타입변경 불가
let sym = Symbol(); try { +sym; } catch { console.log("타입변경 불가"); }; // 타입변경 불가
단항연산자 +를 통해 Number로 타입을 바꾸려 시도하지만 예외가 발생합니다. 이는 외부에 값이 노출되지 않게 하기 위해서입니다.
-
파라미터에 보통 주석, 설명을 작성
const sym = Symbol("주석, 설명"); console.log(sym); // Symbol(주석, 설명)
생성한 Symbol 값을 볼 수 없으므로 값 설명이 필요할 때 사용합니다. Symbol 실행에 영향을 미치지 않습니다.
-
Symbol 값을 문자열로 변환하여 연결
const sym = Symbol("설명"); console.log(sym.toString() + "연결"); try { const str = new String(sym); } catch { console.log("에러 발생"); } // Symbol(설명)연결
에러가 발생하지 않지만, 값은 변환되지 않고 값을 만든 코드형태에 문자열을 연결합니다. new String(sym) 형태는 에러가 발생합니다.
-
Symbol은 Template에 사용 불가
const sym = Symbol("주석, 설명"); try { `${sym}` } catch { console.log("`${sym} 불가`"); }; // `${sym} 불가`
여기서 Template안에 Symbol()을 넣으면 에러가 발생하는데, 이는 Teamplate에서 sym내부의 값을 꺼내서 파싱하려할 때 에러가 발생하기 때문입니다.
Symbol 사용 형태
-
Object의 프로퍼티 키로 사용
Symbol은 프로젝트 전체에서 유일한 값을 가집니다. 그렇기에 중복되지 않습니다.const pointSym = Symbol("가격"); const obj = {[pointSym]: 100}; console.log(obj[pointSym]); console.log(obj.pointSym); // 100 // undefined
⇒ Symbol값을 Object의 프로퍼티 키로 작성해 사용할 수 있는데 이를 symbol-keyed property라 부릅니다.
⇒ 주의할 사항은 Symbol 프로퍼티는 객체 그래프 탐색(.)으로 접근할 수 없으며, 대괄호를 통해 접근해야 합니다.
⇒ obj.pointSym은 undefined가 출력됩니다. -
Object에서 함수 이름으로 사용
사용법 자체는 프로퍼티 키로 사용하는것과 유사합니다.const plusSym = Symbol("plus100"); const obj = { [plusSym](param) { return param + 100; } }; console.log(obj[plusSym](200)); // 300
⇒ 함수 이름도 실행 콘텍스트의 환경레코드에는 프로퍼티(key): 값(value)로 저장되기 때문에 식별자 해결을 통해 값(함수)를 호출한다는 점에서 유사합니다.
-
for-in문에서 사용
Symbol의 내부 프로퍼티 중 [[Enumerable]]은 false입니다. 그렇기에 Symbol은 열거되지 않습니다. Object.getOwnPropertySymbols()로 심볼만 열거하는 것으로 보완합니다.const hundred = Symbol("100"); const obj = { [hundred] : 100, two: 200 }; for (let key in obj) { console.log(key); }; // two
-
for-of문에서 사용
배열 안에 Symbol()를 작성할 경우, 순회는 가능합니다.const list = [Symbol("1"), Symbol("2")]; for(let value of list) { console.log(value); }; // Symbol(1) // Symbol(2)
-
JSON.stringify()에서 사용
JSON.stringify()는 object의 프로퍼티 키와 값을 {"key": "value"} 형태로 변환합니다. stringify()를 통해 직렬화를 할 때 Symbol()의 값이 노출되기 때문에, 변환을 시도하면 Symbol은 변환에서 제외됩니다. Symbol값은 문자열로 변환되지 않습니다.const sym = Symbol("JSON"); const result = JSON.stringify({[sym]: "ABC"}); console.log(result); // {}
Author And Source
이 문제에 관하여([JS] #12 Symbol 오브젝트), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@simoniful/JS-12-Symbol-오브젝트저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)