자바스크립트 객체의 프로퍼티 키는 오직 문자형만을 허용하는데, 추가적으로 한가지 더 가능하다.
그것이 바로 심볼형
이다.
심볼은 유일한 식별자
를 만들고 싶을 때 사용한다.
심볼은 Symbol()
의 문법을 사용한다.
심볼을 만들 때는 심볼 이름이라고 부르는 설명을 붙일 수 있다.
심블의 이름은 디버깅에서 유용하게 사용한다.
// 심볼id에는 "id"라는 설명이 붙는다.
let id = Sumbol('id');
심볼은 유일성
이 보장되는 자료형이다.
설명이 동일한 여러개의 심볼을 만들어도 다 다른값이 된다.
심볼에 붙이는 설명은 그저 이름표 역활만 할 뿐이다.
let id1 = Symbol('id');
let id2 = Symbol('id');
console.log(id1 == id2); // false
console.log(id1 === id2); // false
자바스크립트에서는 문자형으로 암시적 형 변환이 자유롭게 일어난다.
하지만 심볼은 예외적이다. 심볼형 값은 다른 자료형으로 자동 형변환이 일어나지 않는다.
let id = Symbol('id');
alert(id); // TypeError
alert는 매개변수를 문자형으로 자동 형 변환을 하기 때문에
Symbol형이 들어오면 에러가 발생한다.
문자열과 심볼은 근본이 다르기 때문에 서로의 타입으로 변환돼선 안된다.
언어 차원의 보호장치
를 마련하여 심볼형이 다른 형으로 변환되지 않게 막아준다.
심볼을 반드시 출력해줘야 한다면 .toString()
메서드를 명시적으로 호출해 주면 된다.
let id = Symbol('id');
alert(id.toString());
또한 .description
을 사용하면 설명만을 보여줄 수 있다.
let id = Symbol('id');
alert(id.description);
심볼을 이용한다면 숨김(hidden) 프로퍼티를 만들 수 있다.
숨김 프로퍼티는 외부 코드에서 접근이 불가능하고 덮어쓰기도 불가능하다.
서드파티 코드(외부에서 만들어진 라이브러리 등)에서 가져온 user라는 객체가 여러개 있고, user를 이용해 작업을 해야하는 상황이라고 가정하고, user에게 식별자를 붙여준다면
let user = { // 서드파티 코드에서 가져온 객체
name: 'quakka'
};
let id = Symbol("id");
user[id] = 1;
alert(user[id]); // 심볼을 키로 사용하여 데이터에 접근할 수 있다.
여기서 식별자를 심볼형으로 사용한 이유는?
우선 user
는 외부에서 가지고 온 객체이다. 마음대로 프로퍼티를 추가할 수 없기 때문에 심볼을 사용했다.
심볼은 서드파티 코드에서 접근할 수 없기 때문에, 우리만 아는 식별자를 추가할 수 있는 것이다.
이것은 해당 user라는 객체를 여러곳에서 사용할 때 더 유용한다.
만약 서드파티 코드, 현재 작성 중인 스크립트, 다른 제3의 스크립트에서 해당 user
객체를 식벼해야하는 상황이라면
문자열로 'id'를 주는것은 위험하다. 덮어쓰기가 될 수 있기 때문이다.
이러한 상황에서도 심볼타입을 준다면 완벽히 구분할 수 있다.
키가 심볼일 경우는 for...in 반복문에서 배제된다.
let id = Symbol("id");
let user = {
name: "quakka",
age: 29,
[id]: 123 // 리터럴에서 심볼을 주기위해 대괄호를 사용
};
for(let key in user) { console.log(key) };
//name, age
심볼은 이름이 같더라도 다른것으로 인식된다.
하지만 이름이 같은 심볼이 같은 개체를 가르키길 원하는 경우도 있다.
애플리케이션 곳곳에서 심볼 "id"를 이용해 특정 프로퍼티에 접근해야 한다면, 전역 심볼 레지스트리
를 이용한다.
전역 심볼 레지스트리 안에 심볼을 만들고 해당 심볼에 접근하면, 이름이 같은 경우 항상 동일한 심볼을 반환한다.
전역 심볼 레지스트리에 새로운 심볼을 생성하려면
Symbol.for(key)
를 사용하면 된다.
만약 해당 key의 심볼이 존재한다면 그 심볼을 읽어온다.
//전역 레지스트리에서 심볼을 읽는다.
let id = Symbol.for("id"); // 만약 없다면 생성 후 읽어온다.
//동일한 key를 이용해 같은 심볼을 읽어 온다.
let idAgain = Symbol.for("id");
console.log(id === idAgain); // true
Symbol.keyFor(key)
를 사용한다.// 전역 심볼을 읽음 또는 생성 후 읽음
let sym1 = Symbol.for("name");
let sym2 = Symbol.for("id");
// 전역에서 받아온 심볼의 이름을 읽음
console.log(Symbol.keyFor(sym1)); // name
console.log(Symbol.keyFor(sym2)); // id
전역심볼이 아닐경우에는 undefined가 반환됨
전역심볼이 아닐경우에는.description
으로 접근