Symbol
은 뭘까?Symbol
만 가능하다는데,Symbol
이 뭐길래?오늘은 Symbol
에 대해 알아보자.
Symbol
단어 자체가 낯설 수 있다. 나 역시 그랬음.
Symbol
은 Computer Programming적으로 다음과 같은 의미를 갖는다.
Symbol이란, 그 인스턴스가 사람이 읽을 수 있는 형태의 고유한 식별자를 갖는 원시 데이터 타입이다.
뭔가 식별자의 역할을 해주겠거니로 이해하고 넘어가보자.
다른 언어들에서는 atom
이라는 이름으로 불리기도한다.
우선 심볼을 생성해보자.
심볼은 class-like
한 형태로 제공되지만 new
연산자로 인스턴스를 생성할 수 없다. 전역적인 심볼 영역에 영향을 끼칠 수 있기 때문에 제한된 것인데, 이게 무슨 의미인지는 차근차근 이해해보자.
const badSymbol = new Symbol('TestSymbol') // Error
const goodSymbol = Symbol('TestSymbol');
goodSymbol을 생성한 방법처럼 심볼을 생성할 수 있다.
이렇게 생성된 심볼의 프로토타입을 한 번 확인해보자.
Object.getPrototypeOf(goodSymbol);
뭔가 Symbol 과 관련된 건 for
keyFor
이 두개의 메서드 정도밖에 보이지 않는다.
이 for
과 keyFor
메서드가 위에서 언급한 전역심볼영역과 연관되어 있다. 차차 알아보고 우선은 이 심볼을 사용해 무언갈 해보자.
MDN에서도 나와있듯이 심볼은 식별자로 이용이 가능한 원시 데이터 타입. 그게 전부이다.
그럼 이 식별자로서 심볼을 사용하는 것이 무슨 이득을 주는걸까?
const obj = {};
const sym = Symbol('age');
obj[sym] = 50;
obj.age // undefined
obj[sym] // 50
위처럼 age
라는 심볼을 생성한 뒤 obj
의 키 값으로 설정했다.
이렇게 보면 아니 이거 왜 써요 도대체?? 이런 생각이 들지도 모름.
심볼인 키값과 그렇지 않은 키값은 무슨 차이가 있을까?
const obj = {};
const sym = Symbol('age');
const otherSym = Symbol('age')
sym === otherSym // false
같은 토큰('age'
)으로 생성한 심볼이더라도 서로 다르다.
이 유니크하다는 특성이 어떤 장점을 가져올 수 있을까?
아래와 같이 someModule
이라는 외부에서 가져온 코드가 있을 때, 사용하는 우리 입장에서는 이 객체의 내부가 어떻게 생겼는 지 모른다고 가정해보자.
그런데 우리의 요구사항 중에 이 객체를 식별해야하는 상황이 필요해서 임의로 id
프로퍼티를 추가한다면 ?
const someModule = { id: 2, name: 'John Doe' };
// ----------- using this module -----------
someModule.id = 'myid'
외부 코드의 기존 동작에 영향을 줄 수도 있게 된다.
이제, 심볼을 통해서 정의해보도록 하자.
const someModule = { id: 2, name: 'John Doe' };
// ----------- using this module -----------
const id = Symbol('id');
someModule[id] = 'myid';
이렇게 심볼을 정의할 경우 외부 코드의 기존 동작에 영향을 주지 않으면서 몰래(?) 프로퍼티를 추가할 수 있다.
const sym = Symbol('test');
const obj = {
[sym]: 1234,
name: 'John Doe',
status: 'hungry',
};
Object.keys(obj) // ['name', 'status']
for (const el in obj) { console.log(el) } // ['name', 'status']
위처럼 객체를 순회할 때 심볼은 나타나지 않는다.
만약 sym
변수를 모른다면 obj
의 [sym] 안에 저장되어있는 1234라는 값은 조회할 수 없다. (지금까지의 지식만으로는)
지금까지의 내용으로 미루어보았을 때 심볼은 다음과 같다.
그래서 그런지 여러 곳에서 접근이 가능한 심볼 값을 만들기란 다소 어려워보인다.
이 때, 같은 토큰 값으로 만든 심볼이 서로 같은 값을 가질 수 있도록 하는 방법이 존재한다.
전역심볼영역을 사용하는 것이다.
위에서 Symbol의 프로토타입을 살펴보면서 생성자 안에 for
, keyFor
메서드가 있는 것을 확인했다.
각 메서드의 역할을 간단히 설명하자면 다음과 같다.
Symbol.for(token)
: 전역심볼영역에서 token에 해당하는 심볼을 반환한다,Symbol.keyFor(sym)
: 전역심볼영역에서 sym이 갖고 있던 토큰을 반환한다.Symbol.keyFor(Symbol.for('test')) === 'test'
위의 메서드를 사용하여 전역심볼영역에 접근하게 된다면 같은 토큰 값으로 만든 심볼이 서로 같은 값을 가질 수 있게 된다.
const sym = Symbol.for('id');
object[sym] = 1234;
// --------- other space ---------
const mySym = Symbol.for('id');
object[mySym] === 1234 // true
Well-known symbols are built-in Symbol values that are explicitly referenced by algorithms of this specification. They are typically used as the keys of properties whose values serve as extension points of a specification algorithm. Unless otherwise specified, well-known symbols values are shared by all realms (9.3). - ECMAScript
오늘 알아본 심볼들은 자바스크립트의 내장 기능들을 구현하는 곳에서 사용되고 있다. 이 중에 잘 알려진 심볼들을 well-known symbol
이라고 한다.
well-known symbol의 리스트는 ECMAScript 명세에서 찾아볼 수 있다.