자바스크립트에는 7개의 데이터 타입이 존재합니다.
원시 타입: 문자열, 숫자, 불린, undefined
, null
, 심볼
그리고
객체 타입(참조 타입 (함수, 객체, 배열 등))
심볼은 ES6에 추가된 새로운 원시 타입입니다.
원시값들은 리터럴로 값을 생성할 수 있지만 심볼 값은 Symbol 함수를 호출해서 생성해야 합니다.
생성된 심볼 값은 다른 값과 중복되지 않는 유일성이 보장되는 값입니다. 또한 심볼 값은 외부로 노출되지 않아서 값을 확인할 수 없습니다.
심볼은 유일한 식별자를 만들기 위해 사용합니다.
let id = Symbol();
console.log(typeof id); // symbol
console.log(mySymbol); // Symbol(), 심볼 값은 외부로 노출되지 않아서 값을 확인할 수 없음
함수를 호출해서 객체를 생성하는 것처럼 보이지만 new
연산자와 함께 호출하지 않습니다.
new
키워드와 생성자 함수 혹은 클래스를 호출하면 객체가 생성되지만 심볼 값은 원시 값입니다.
선택적으로 문자열을 인수로 전달하여 심볼 설명(key)을 붙일 수도 있습니다.
심볼 설명(key)은 디버깅 시에 유용하며, 심볼 값 생성에는 어떠한 영향도 주지 않습니다.
let id = Symbol('id');
심볼은 유일성이 보장되기 때문에 키가 동일한 심볼을 여러 개 만들어도 각 심볼 값은 다릅니다.
let id1 = Symbol("id");
let id2 = Symbol("id");
console.log(id1 === id2); // false
또한 심벌은 다른 자료형으로 자동 형 변환이 일어나지 않습니다.
따라서 객체를 console.log
로 찍었을 때 문자열로 변환되어 보여주었던 것과 달리 심볼은 자동으로 문자열 변환이나 숫자 타입 변환이 일어나지 않습니다.
심볼을 반드시 출력해야 한다면 .toString()
을 명시적으로 호출해야 합니다.
심볼 값은 원시값이기 때문에 숫자, 문자열, 불린과 같이 객체처럼 접근하면 래퍼 객체를 생성합니다. 래퍼 객체는 메서드, 프로퍼티 등을 제공하고 다시 사라집니다.
toString
메서드와 description
프로퍼티는 Symbol.prototype
의 프로퍼티입니다.
let id = Symbol("id");
console.log(id.toString()); // Symbol(id)
symbol.description
프로퍼티는 심볼 설명(key)을 나타냅니다.
let id = Symbol("id");
console.log(id.description); // id
심볼은 유일성을 보장하기 때문에 심볼 설명(key)이 같더라도 심볼값은 다릅니다.
하지만 같은 키를 가지는 심볼 값이 항상 같은 심볼 값을 가지도록 할 수 있습니다.
이를 위해서는 '전역 심볼 레지스트리'에 심볼 값을 만들면 됩니다.
전역 심볼 레지스트리는 자바스크립트 엔진이 관리하는 심볼 값 저장소입니다.
전역 심볼 레지스트리에 등록된 심볼을 전역 심볼이라고 합니다.
애플리케이션 전역에서 중복되지 않는 유일무이한 심볼 값을 단 하나만 생성하여 전역 심볼 레지스트리를 통해 공유할 수 있습니다.
전역 심볼 레지스트리 안에 심볼 값을 생성하기 위해서는 Symbol.for(key)
를 사용하면 됩니다.
key와 일치하는 심볼값을 검색하고 없는 경우 심볼 값을 생성합니다.
생성한 심볼 값을 전달받은 key로 저장하고 심볼값을 반환합니다.
검색에 성공한 경우(key와 일치하는 심볼 값을 찾은 경우)는 검색된 심볼 값을 반환합니다.
// 전역 레지스트리에서 심볼을 읽습니다.
let id = Symbol.for("id"); // 심볼이 존재하지 않으면 새로운 심볼을 만듭니다.
// 동일한 이름을 이용해 심볼을 다시 읽습니다.
let idAgain = Symbol.for("id");
// 두 심볼은 같습니다.
alert( id === idAgain ); // true
Symbol.keyFor(symbol)
는 symbol을 받아서 전역 심볼 레지스트리에서 심볼을 찾은 후 그 심볼의 이름을 반환해줍니다.
전역 심볼이 아닌 심볼을 넘겨주면 전역 심볼 레지스트레이서 찾을 수 없기 때문에 undefined
를 반환합니다.
전역 심볼이 아닌 심볼은 description
프로퍼티를 가지고 있기 때문에 일반 심볼의 설명(key)을 얻고 싶다면 description
프로퍼티를 사용해야 합니다.
Symbol.keyFor
는 전역 레지스트리에서 찾기 때문에 전역 심볼이 아닌 심볼에는 사용할 수 없습니다.
일반 심볼도 Symbol()
를 호출하여 생성하지만 이 심볼 값은 검색할 수 있는 키가 전역 심볼 레지스트리에 없기 때문입니다.
프로퍼티 키를 심볼형으로 사용했을 때의 이점에 대해 알아보겠습니다.
자바스크립트 객체의 키는 문자열과 심볼만 허용합니다.
심볼 값을 프로퍼티 키로 사용해봅시다.
const obj = {
[Symbol.for('mySymbol')]: 1
};
console.log(obj[Symbol.for('mySymbol')]); // 1
심볼 값은 유일하기 때문에 심볼 값으로 프로퍼티 키를 만들면 다른 그 어떤 프로퍼티 키와 절대로 충돌할 일이 없습니다.
심볼을 사용해 숨김(hidden) 프로퍼티를 만들 수 있습니다.
프로퍼티 키가 심볼 값인 경우 해당 객체를 가지고 for...in
, 혹은 Object.keys
, Object.getOwnPropertyNames
등의 메서드를 사용했을 때 심볼 프로퍼티 키는 제외되어 찾을 수 없습니다.
const obj = { // 서드파티 코드에서 가져온 객체
[Symbol('mySymbol')]: 1
};
for (const key in obj) {
console.log(key) // 아무것도 출력되지 않음
}
console.log( Object.keys(obj) ); // []
console.log( Object.getOwnPropertyNames(obj)); // []
ES6에서 도입된 Object.getOwnPropertySymbols
메서드를 사용하면 심볼 프로퍼티를 키로 가진 프로퍼티를 찾을 수 있습니다.
자바스크립트가 기본으로 제공하는 빌트인 심볼 값을 Well-known Symbol이라고 부릅니다.
Array, String, Map, Set, arguments 등의 for...of
문으로 순회 가능한 빌트인 이터러블은 Well-known Symbol인 Symbol.iterator
를 키로 갖는 메서드를 가집니다.
Symbol.iterator
메서드를 호출하면 이터레이터를 반환하도록 ECMAScript 사양으로 정해져 있습니다.
빌트인 이터러블 객체는 이러한 규정(이터레이션 프로토콜)을 준수합니다.
이터러블이 아닌 일반 객체를 이터러블처럼 동작하도록 구현하려면 Symbol.iterator
를 키로 갖는 메서드를 객체에 추가하고 이터레이터를 반환하도록 구현하면 됩니다.
console.dir(Symbol);
심볼 함수를 참조하면 ECMAScript 사양에 정의된 여러 Well-known Symbol을 확인해볼 수 있습니다.
보통은 표준 빌트인 객체를 확장하여 사용자 정의 메서드를 추가하거나 하는 것을 권장하지 않습니다.
아니 그냥 하지 않아야 합니다.
임의로 사용자 정의 메서드를 추가한다면, 나중에 ECMAScript 사양에서 추가할 메서드 이름(프로퍼티 키)와 겹친다면 ECMAScipt 사양으로 추가된 메서드가 사용자 정의 메서드로 덮어씌워져 사용할 수 없게 됩니다.
하지만 심볼을 키로 메서드를 정의한다면 키가 겹치지 않기 때문에 확장할 수 있습니다.
심볼값은 원시값이며 함수를 호출해서 생성할 수 있습니다.
심볼을 생성할 때 인수로 넘겨주는 문자열은 심볼 설명 값(key)으로 사용됩니다.
전역 심볼 레지스트리에 심볼 값을 생성하고 이 심볼 값을 검색할 key로 심볼 값을 저장하여 유일한 심볼값을 애플리케이션 전역에서 공유할 수 있습니다.
또한 심볼값은 프로퍼티 키로 사용할 수 있으며 이런 심볼 프로퍼티 키는 순회 동작에서 제외됩니다.
ES6에 추가된 Object.getOwnPeropertySymbol
메서드를 사용하면 심볼 프로퍼티도 찾을 수 있습니다.
심볼을 키로 가지는 메서드를 작성하여 표준 빌트인 객체를 확장할 수도 있으며,
객체에 Symbol.iterator
를 키로하는 메서드가 존재하고 이 메서드가 이터레이터를 반환한다면 이 객체는 이터러블처럼 동작하게 됩니다.
빌트인 이터러블 객체는 이런 이터레이션 프로토콜을 준수하고 있습니다.
다음 포스팅에서는 이터러블과 이터레이션 프로토콜에 대해 알아보겠습니다.