Javascript Primitive

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

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

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

Symbol

1
2
const helloSymbol = Symbol();
const hiSymbol = Symbol();

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

1
2
3
4
let obj = {};
obj[helloSymbol] = "hello";
obj[hiSymbol] = "hi";
console.log(obj);

1
{Symbol(): "hello", Symbol(): "hi"}

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

1
2
const welcomeSymbol = Symbol("환영합니다");
console.log(welcomeSymbol);

1
Symbol(환영합니다)

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

예제

1
2
3
4
5
6
7
const isBlocked = Symbol("is blocked element?");

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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);
}

1
2
3
4
5
6
"영문명"
"별명"
"영문명"
"별명"
"영문명"
"별명"

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

1
Object.getOwnPropertySymbols(메시);

1
[Symbol(선수의 국적)]

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

1
Reflect.ownKeys(메시);

1
["영문명", "별명", Symbol(선수의 국적)]

Reflect.ownKeys를 활용하면 된다.

심볼의 특징

  • 일단 생성되면 변경되지 않는다
  • 속성을 부여할 수 없다
  • object의 key 값으로 사용할 수 있다.
  • 모든 심볼은 고유하다. 주석이 동일하다 하더라도 일단 생성되면 다르게 구별된다.
  • 문자열로 자동으로 변환되지 않는다.

1
2
3
4
5
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 처럼 표준에 정의된 심볼을 가져오는 법