목차
JavaScript Symbol
변경 불가능한 원시타입의 값이다. 주로 변수명이 충돌 위험이 없는 유일한 객체의 Property Key를 만들기 위해 사용되며 Symbol 함수를 호출하여 생성한다.
//symbol key는 이름 충돌 위험이 없는 유일한 객체의 property key 이다.
let key = Symbol('key');
console.log(key);
console.log(typeof key); //symbol
var obj = {};
obj[key] = 'value';
console.log(obj[key]); //value
[결과]
Symbol(key)
symbol
value
Symbol('key')의 문자열 설명은 디버깅에 쓰일 뿐 식별자가 아니다. 같은 설명으로 두 번 생성해도 값은 다르다.
const first = Symbol('id');
const second = Symbol('id');
console.log(first === second); // false
const user = { id: 10, [first]: '내부 표시' };
console.log(user.id); // 10
console.log(user[first]); // 내부 표시
console.log(Object.keys(user)); // ['id']
심벌 키는 일반적인 문자열 키 열거와 JSON.stringify 결과에 포함되지 않는다. 그렇다고 접근을 막는 비밀 저장소는 아니다. Object.getOwnPropertySymbols(user)로 찾을 수 있다.
Symbol.for('id')는 전역 심벌 레지스트리에서 같은 키를 재사용하므로 매번 새 값을 만드는 Symbol('id')와 다르다. 라이브러리 사이에 심벌을 공유하려는 목적이 아니라면 보통 독립적인 Symbol()을 쓴다. 언어가 제공하는 Symbol.iterator 같은 잘 알려진 심벌은 객체의 동작을 확장하는 데 사용된다.
열거와 직렬화에서 보이는 범위
심벌 키는 Object.keys, for...in, 일반적인 JSON.stringify 결과에는 나타나지 않는다. 하지만 숨겨진 비밀 키는 아니다. Object.getOwnPropertySymbols나 Reflect.ownKeys로 찾을 수 있다. 객체를 다른 코드에 넘기면서 심벌 키를 비밀 정보 저장소로 쓰면 접근 통제를 제공하지 못한다.
const mark = Symbol("mark");
const record = { id: 7, [mark]: "내부" };
console.log(Object.keys(record)); // ['id']
console.log(Reflect.ownKeys(record)); // ['id', Symbol(mark)]
console.log(JSON.stringify(record)); // {"id":7}
위 출력은 일반적인 객체 열거와 심벌을 포함한 키 조회의 차이를 보여 준다. 직렬화 뒤 복원한 객체에는 심벌 키가 없으므로, API로 전송해야 하는 데이터에는 문자열 키를 써야 한다. Symbol.for("app.status")는 같은 키를 공유하는 코드를 의도적으로 연결할 때 사용한다. 이 이름도 전역 레지스트리 안에서 충돌할 수 있으므로 패키지 또는 앱 이름을 접두어로 두는 편이 좋다. 매번 독립적인 키가 필요하면 Symbol("status")를 선택한다.
참고: MDN Symbol, MDN Symbol.for