avatar
Published on

Javascript Symbol

Author
  • avatar
    Name
    yceffort

Javascript Primitive

기존에 자바스크립트는 6가지의 primitive가 있었다.

  • Object
  • string
  • number
  • boolean
  • null
  • undefined

그러나 es6가 들어서면서 symbol이라는 7번째 primitive가 추가되었다.

Symbol

const helloSymbol = Symbol()
const hiSymbol = Symbol()

새로운 심볼 값을 생성했다. 이 심볼로 생성한 값은 변경할 수 없으므로 const에 할당에도 상관없다. 그리고 이렇게 생성된 심볼 값은 프로그램 내에서 유일함을 보장해 준다.

let obj = {}
obj[helloSymbol] = 'hello'
obj[hiSymbol] = 'hi'
console.log(obj)
{Symbol(): "hello", Symbol(): "hi"}

물론 문자열이나 숫자를 key로 사용할 수 있지만, symbol은 유일함을 보장해주기 때문에 이렇게 키값으로 사용할 수 있다.

const welcomeSymbol = Symbol('환영합니다')
console.log(welcomeSymbol)
Symbol(환영합니다)

Symbol안에 있는 문자열은 일종의 주석으로 보면 될 것 같다.

예제

const isBlocked = Symbol('is blocked element?')

if (element[isBlocked]) {
  openElement(element)
} else {
  element[isBlocked] = true
}

elementisBlocked라는 심볼을 키로 갖는 object다. 문자열이나 숫자가 아닌 심볼을 key로 갖는 속성이다. 이는 유일성을 보장해주기 때문에 다른 키들과의 충돌을 방지할 수 있다. 다만 obj.name과 같이 dot을 이용해서 접근할 수 없다. 반드시 []를 활용해서 접근해야 한다.

한가지 주의 해야할 것은 isBlocked 심볼 값이 스코프 내에 존재 할 때만 이러한 행위가 가능하다는 것이다. 어떤 모듈이 심볼을 스스로 만드는 경우, 해당 모듈은 해당 심볼을 모든 객체에 적용할 수 있다. 즉 다른 속성과의 충돌을 걱정할 필요가 없다.

그리고 심볼 키는 이러한 충돌을 방지하기 위해서 만들어 진 것이므로, 일반적인 javascript 객체 조사는 Symbol을 무시한다. 무슨 소리냐면...

let 메시 = {}
메시['영문명'] = 'Lionel Messi'
메시['별명'] = '라이오넬 멧시'
const Nationality = Symbol('선수의 국적')
메시[Nationality] = '칠레'

for (let i in 메시) {
  console.log(i)
}

for (let i of Object.keys(메시)) {
  console.log(i)
}

for (let i of Object.getOwnPropertyNames(메시)) {
  console.log(i)
}
"영문명"
"별명"
"영문명"
"별명"
"영문명"
"별명"

이처럼 심볼 Nationality 키는 일반적인 상황에서 모두 무시 되는 것을 볼 수 있다. 물론 이를 조회하는 방법도 있다.

Object.getOwnPropertySymbols(메시)
[Symbol(선수의 국적)]

혹은 심볼을 포함해서 모든 키를 조회하고 싶다면

Reflect.ownKeys(메시)
["영문명", "별명", Symbol(선수의 국적)]

Reflect.ownKeys를 활용하면 된다.

심볼의 특징

  • 일단 생성되면 변경되지 않는다
  • 속성을 부여할 수 없다
  • object의 key 값으로 사용할 수 있다.
  • 모든 심볼은 고유하다. 주석이 동일하다 하더라도 일단 생성되면 다르게 구별된다.
  • 문자열로 자동으로 변환되지 않는다.
const newSymbol = Symbol(
  'this symbol',
)`symbol is ${newSymbol}` //Uncaught TypeError: Cannot convert a Symbol value to a string
`symbol is ${String(newSymbol)} ${newSymbol.toString()}`
// symbol is Symbol(this symbol) Symbol(this symbol)

심볼을 갖는 방법

  • Symbol()을 호출한다. 이는 호출할 때 마다 새롭고 고유한 심볼을 만들어 준다.
  • Symbol.for(string)을 호출한다. 이 메소드는 Symbol Registry라는 심볼목록을 참조하여 리턴하는데, 앞서와는 다르게 심볼 목록을 공유한다. Symbol.for('호날도')를 계속해서 호출한다면, 매번 같은 심볼을 리턴한다. 이는 심볼이 공유 되어야 하는 상황에서 유용하다.
  • Symbol.length 처럼 표준에 정의된 심볼을 가져오는 법