자바스크립트의 심볼(Symbol)
은 ES6에서 새롭게 추가된 변경 불가능한 원시 타입의 값
이다.
객체의 프로퍼티 키로는 문자형과 심볼형만 허용한다. 객체의 프로퍼티 키로 심볼값을 사용하면 어떤 장점이 있는지 알아보자.
Symbol
은 유일한 식별자를 만들고 싶을 때 사용한다. Symbol
은 Symbol() 함수
로 생성할 수 있다. 이때 생성된 Symbol 값은 객체가 아닌 변경 불가능한 원시 타입
이다.
let id = Symbol();
console.log(id); // Symbol()
console.log(typeof id); // Symbol
Symbol
을 만들 때 Symbol
의 설명을 붙일 수 있다. Symbol
의 설명은 디버깅 시 아주 유용하게 사용된다.
let id = Symbol('id symbol description');
console.log(id); // Symbol(id symbol description)
Symbol
은 유일한 식별자이므로 같은 설명을 가진 Symbol
두 개를 만들고 비교해도 동일 연산자 비교 시 false
가 반환된다.
let id1 = Symbol('id1 symbol description');
let id2 = Symbol('id2 symbol description');
console.log(id1 == id2); // false
Symbol
값은 객체의 프로퍼티 키로 사용할 수 있다. Symbol값은 유일한 값으로 Symbol을 키로 갖는 프로퍼티는 다른 어떤 프로퍼티와도 충돌하지 않는다.
const obj = {};
const mySymbol = Symbol('mySymbol');
obj[mySymbol] = 123;
console.log(obj) // { [Symbol(mySymbol)]: 123 }
console.log(obj[mySymbol]); // 123
Symbol()
로 Symbol
값을 생성할 수 있다. 이것은 Symbol
이 함수 객체라는 것을 의미한다.
Symbol
함수 객체는 프로퍼티와 메소드를 가지고 있다. Symbol
객체의 프로퍼티 중 length와 prototype을 제외한 프로퍼티를 Well-Known Symbol 이라 부른다.
Well-Known Symbol은 자바스크립트 엔진에 상수로 존재하며 Well-known-Symbol을 참조하여 일정한 처리를 한다.
예를 들면, 어떤 객체가 Symbol.iterator
를 프로퍼티 키로 사용한 메소드를 가지고 있으면, 자바스크립트 엔진은 이 객체가 이터레이션 프로토콜
을 따르는 것으로 간주하고 이터레이터
로 동작하도록 한다.
Symbol.iterator를 프로퍼티 키로 사용해여 메소드를 구현하고 있는 객체는 아래와 같다. 아래의 객체들은 이터레이션 프로토콜을 준수하고 있으며 이터레이터를 반환한다.
Array.prototype[Symbol.iterator]; // Array
String.prototype[Symbol.iterator]; // String
Map.prototype[Symbol.iterator] // Map
Set.prototype[Symbol.iterator] // Set
NodeList.prototype[Symbol.iterator] // DOM data structures
HTMLCollection.prototype[Symbol.iterator] // DOM data structures
이터러블은 Symbol.iterator를 프로퍼티 키로 가지고 있는 객체
이다. 배열에는 Array.prototype[Symbol.iterator] 메소드가 구현되어 있다.
const iterable = ['a', 'b', 'c'];
Symbol.iterator를 프로퍼티 키로 가지고 있는 메소드는 이터레이터를 반환
한다. 이터레이터는 순회 가능한 자료 구조인 이터러블의 요소를 탐색하기 위한 포인터로 value, done 프로퍼티를 갖는 객체를 반환하는 next() 함수를 메소드로 갖는 객체
이다.
const itertator = iterable[Symbol.iterator];
console.log(iterator.next()); // { value: 'a', done: false }
console.log(iterator.next()); // { value: 'b', done: false }
console.log(iterator.next()); // { value: 'c', done: false }
console.log(iterator.next()); // { value: undefined, done: true }
Symbol.for
메소드는 인자로 전달받은 문자열을 키로 사용하여 Symbol 값들이 저장되어 있는 전역 Symbol
레지스트리에 해당 키와 일치하는 저장된 Symbol
값을 검색한다.
검색에 성공하면 Symbol
값을 반환하고, 실패하면 새로운 Symbol
값을 생성하여 해당 키로 전역 Symbol
레지스트리에 저장 후 Symbol
값을 반환한다.
// 전역 Symbol 레지스트리에 foo 라는 키로 저장된 Symbol이 없으면 새로운 Symbol 생성
const s1 = Symbol.for('foo');
// 전역 Symbol 레지스트리에 foo 라는 키로 저장된 Symbol이 있으면 해당 Symbol 반환
const s2 = Symbol.for('foo');
Symbol
함수는 매번 다른 Symbol 값을 생성하지만, Symbol.for
메소드는 하나의 Symbol
을 생성하여 여러 모듈이 키를 통해 같은 Symbol
을 공유할 수 있다.
Symbol.for
메소드를 통해 생성된 Symbol
값은 반드시 키를 가진다. Symbol
함수를 통해 생성된 값은 키가 없다.
Symbol
함수는 유일한 식별자인 Symbol
값을 반환하고 Symbol
값은 객체의 프로퍼티 값으로 사용해서 어떤 프로퍼티와도 충돌하지 않게 사용할 수 있다.
Symbol.iterator
메소드를 가지고 있는 객체를 이터러블 이라고 부르며 Symbol.iterator
메소드는 이터레이터를 반환한다. 이터레이터는 순회 가능한 자료 구조인 이터러블 요소를 탐색하기 위해 value, done
프로퍼티를 반환하는 next()
함수를 가진다.