ES6의 Symbol

심재철
7 min readJul 20, 2020

--

ES6에서 number, boolean, string, undefined, null, object 이외에 7번째 새로운 자료 구조인 Symbol이 등장했다.

Symbol

심볼은 unique id를 생성해주는 factory 함수라고 생각하면 편하다.

let symbol2 = Symbol('simsimjae');

이런식으로 simsimjae라고 하는 이름을 가진 심볼을 생성할 수 있다. 여기서 ‘simsimjae’의 역할은 심볼에 이름을 붙인거(description)라고 생각하면 된다. 따라서 같은 이름을 가진 심볼을 2개를 만들었다고 해서 그 두개의 심볼이 같은것은 아니다.

Symbol('simsimjae') !== Symbol('simsimjae')

왜냐면 심볼은 생성할때마다 유니크한 값이 되기 때문이다.

Symbol의 사용처

객체의 property key로 사용된다.

const SymbolPropertyKey = Symbol();
let obj = {};
obj[SymbolPropertyKey] = 123;
console.log(obj[SymbolPropertyKey]); // 123

좀 더 간단하게는 이렇게 사용할 수 있다.

const SymbolPropertyKey = Symbol();
let obj = {
[SymbolPropertyKey]: 123
};

좀 더 간단하게는 이렇게 사용할 수 있다.

let obj = {
[Symbol('SymbolPropertyKey')]: 123
};

이런식으로 객체의 메소드를 가리킬수도 있다.

const FOO = Symbol();
let obj = {
[FOO]() {
return 'bar';
}
};
console.log(obj[FOO]()); // bar

FOO라는 심볼(unique한 string값이라고 생각하자.) 메소드를 선언했다.

객체의 키로 string을 사용하게 되면 이런 문제가 발생할 수 있다.

const obj = {
'hello': 'world',
'hello': 'here'
};

나중에 나온 hello key가 그 위에서 선언된 key를 덮어 씌워서

console.log(obj.hello) // "here"를 출력함

이렇게 된다.

그래서 객체의 키로 심볼을 사용하게 될 경우 description이 똑같다 하더라도 매번 고유한 값이 생성되기 때문에 property key가 충돌되지 않을거라고 확신할 수 있다. 심볼은 이런 이름 충돌에 대한 니즈 때문에 탄생하게 되었다.

own property key를 열거하는 방법

ES5까지는 객체의 키로 무조건 string만 사용할 수 있었지만 ES6에서는 심볼을 객체의 키로 사용할 수 있도록 추가되었다. 애초에 심볼의 탄생 목적이 객체의 property key를 unique하게 만들기 위한 목적이라고 한다.

let obj = {
[Symbol('my_key')]: 1,
enum: 2,
nonEnum: 3
};

symbol은 열거가능하지 않다. 여기서 열거의 의미는 for .. in 문이나 object spread에서 확인이 가능한 값이냐는 소리다.

따라서, 만약 아래와 같이

Object.keys(obj)
['enum', 'nonEnum'] 출력

Object.keys를 사용해서 객체의 모든 키를 배열로 만들어도 Symbol은 노출이 되지 않는다. Symbol은 enumerable(열거가능)하지 않기 때문이다.

만약 obj의 nonEnum property도 non enumerable로 만들고 싶으면 아래와 같이 하면 된다.

Object.defineProperty(obj,
'nonEnum', { enumerable: false });

한번 더 Object.keys를 호출해보면

Object.keys(obj)
['enum'] 출력

enum만 출력된다.

객체 내부의 property들을 확인하는 3가지 방법

ES6에서는 객체의 키로 string or Symbol 두가지가 가능하다고 했다. 따라서, 키가 string이냐 Symbol이냐에 따라서 호출해야 하는 함수가 달라진다.

Object.getOwnPropertyNames(obj)

이 함수를 호출하면 객체의 key가 string인것들만 출력해준다. (enum, nonEnum출력)

Object.getOwnPropertySymbols(obj)

이 함수를 호출하면 객체의 key가 Symbol인것들만 출력해준다. ( [Symbol(my_key)] 출력)

만약 key가 Symbol이냐 string이냐에 상관없이 모든 property를 출력하고 싶을땐

Reflect.ownKeys(obj)
[Symbol(my_key), 'enum', 'nonEnum']

이렇게 해주면 된다. Reflect란 (거울) ‘비추다’ 라는 뜻이다. 한마디로 객체 내부를 비춰 뭐가 있는지 확인한다고 생각하면 편하다.

Symbol의 scope

심볼은 우리가 흔히 global scope라고 부르는 것(브라우저에서는 window객체)보다 더 global하다. 아이프레임을 사용해본적이 있는 개발자들은 아이프레임의 scope와 현재 scope가 다르다는것을 알것이다.

function test(arr) {
var iframe = frames[0];

// 아이프레임의 Scope와 현재 javascript의 global Scope는 다르다.
console.log(Array === iframe.Array); // false
console.log(arr instanceof Array); // false, arr은 iframe에서 전달한 배열
console.log(arr instanceof iframe.Array); // true
// 그러나 심볼은 아이프레임과도 scope를 공유한다.
console.log(Symbol.iterator === iframe.Symbol.iterator); // true
}

그래서 우리가 기존에 알고 있던 global은 사실 진짜 global이 아니다. 현재 자바스크립트가 동작하고 있는 호스트 환경(브라우저, 노드)에 따라 global은 얼마든지 변경될 수 있다. 진짜 global한 값을 만들고 싶으면 심볼을 사용해야 한다.

global symbol의 위치

자바스크립트 엔진에는 Symbol registry라고 하는것이 존재한다.

string : Symbolentry로 이루어진 map이라고 생각하면 되는데 엔진에 존재하기 때문에 진짜 global한 값을 만들 수 있다.

이곳에 어떤 심볼을 집어 넣어 두면 모든 영역에서 유일한 값을 저장해놓고 쓸 수 있다.

그렇게 하기 위해서는 아래 메소드를 사용 해야 한다.

let sym = Symbol.for('Hello everybody!'); // Symbol registry에 유니크한 공유 심볼 생성

이 Symbol.for 메소드는 symbol registry에서 Hello everybody!라는 string이 있는지 없는지 찾아본다음에 있으면 그걸 리턴해주고 없으면 새로 만들어주는 메소드이다.

그냥 한마디로 global registry를 찾아보는 메소드라고 생각하자.

Symbol.keyFor(sym)

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

No responses yet

Write a response