자바스크립트의 타입에는 원시타입과 객체타입이 존재한다.
그 중에서 ES6에 추가된 원시타입인 symbol 타입에 대해서 알아보겠다.
Symbol은 symbol 원시값을 반환하는 내장 객체이다. (객체가 값을 반환한다는게 아이러니 하지만...자바스크립트에서는 함수도 객체로 취급하기 때문인 정도로 이해하고 넘어가보자.)
기본적인 심볼의 사용법은 다음과 같다.
const symbol1 = Symbol()
위와 같이 Symbol 내장 객체를 함수로 호출하면 symbol1
이라는 식별자에 symbol 원시값이 할당된다.
다음과 같이 id
라는 식별자를 심볼을 사용하여 유일한 식별자로서 활용할 수 있다.
Symbol 함수는 description을 매개변수로 받는데 이는 심볼을 설명하는 이름표 역할을 할뿐 다른 어떠것에도 영향을 주지 않는다.
const id = Symbol("foo")
typeof id // 'symbol'
cosole.log(id) // Symbol(foo)
또한, 심볼은 문자형으로 자동으로 형변환되지 않기 때문에, 같은 description을 갖는 심볼끼리 비교연산을 했을때 false가 반환된다.
const a = Symbol('심볼')
const b = Symbol('심볼')
a == b // false
a === b // false
심볼의 특징을 정리하면 다음과 같다.
애플리케이션 종료될때까지
)심볼은 위에서 살펴본 특징을 가지고 있기 때문에 객체의 고유한 특성을 만들거나 특정 연산을 사용자화할때 주로 사용된다.
다음과 같이 심볼을 사용해 red 라는 컬러를 고유한 값으로 만들어 상수값으로 활용할 수 있다.
const COLOR_RED = Symbol('red')
다음과 같이 심볼을 활용한 식별자를 객체의 프로퍼티 키로 사용할 수 있다.
심볼을 사용한 프로퍼티는 열가가 불가능하기 때문에 strict 모드에서 객체를 조회시 조회되지 않는다.
객체의 프로퍼티로 추가한 속성은 일반적인 방법으로는 접근할 수 없으므로 약한 형태의 캡슐화, 정보은닉의 효과를 제공할 수 있다.
// strict 모드 기준
const OBJECT_NAME = Symbol('OBJECT_NAME_KEY')
const person = {
[OBJECT_NAME]: '손영산'
}
console.log(person[OBJECT_NAME]) // 손영산
console.log(person) // {}
person.age = 34
console.log(person) // {age: 34}
for(const key in person) console.log(key) // age
console.log(Object.keys(person)); // ["age"]
console.log(Object.getOwnPropertySymbols(person)) // strict: [null] , non-strict: [Symbol('OBJECT_NAME_KEY')]
// 심볼이 포함된 객체의 모드나 프로퍼티를 얻는 방법
console.log([...Object.getOwnPropertyNames(person), ...Object.getOwnPropertySymbols(person)]) // strict: ["age", null], non-strict: ["age", Symbol('OBJECT_NAME_KEY')]
심볼은 크게 글로벌 심볼과 로컬 심볼로 나눌 수 있다.
글로벌 심볼은 Symbol.for()
를 통해서 생성할 수 있고, 해당 글로벌 심볼은 글로벌 심볼 레지스트리에 등록된다. 반면, 로컬 심볼은 글로벌 심볼 레지스트리에 등록되지 않기 때문에 글로벌 심볼을 조회하는 메서드인 keyFor
를 사용했을때 조회할 수 없다.
글로벌 심볼 레지스트리에 등록된 심볼은 iframe, webworker와 같은 환경에서 심볼을 공유해서 고유한 값으로 사용할 수 있다.
const globalSymbol = Symbol.for('GLOBAL_SYMBOL_KEY')
const localSymbol = Symbol('LOCAL_SYMBOL_KEY')
Symbol.keyFor(globalSymbol) // 'GLOBAL_SYMBOL_KEY'
Symbol.keyFor(localSymbol) // undefined
const symbolA = Symbol('symbol')
const symbolB = Symbol('symbol')
const symbolC = Symbol.for('symbol')
const symbolD = Symbol.for('symbol')
console.log(symbolA === symbolB) // false
console.log(symbolA === symbolC) // false
console.log(symbolC === symbolD) // true