프로그래밍 공부하기

Symbol Type 본문

Web/[JS] Common

Symbol Type

ihl 2022. 2. 6. 15:41

  JavaScript의 기본이 되는 6개의 원시 타입은 Number, String, Boolean, null, undefined, Symbol이다. 이 중 Symbol(심볼)에 대해 알아보자.

 

1. Symbol과 기존 JS 객체의 문제점

// 1. No Symbol
const arr = [1,2,3,4,5];
console.log(arr.length); // output: 5

arr.length = 10;
console.log(arr.length); // output: 10

  심볼이란 ES6에서 도입된 원시 타입으로, 유일무이한 값, 고유한 값을 지정하기 위해 사용된다. 위 코드에 나타난 JS의 문제점은 무엇일까? 바로 객체의 내장 속성과 같은 이름으로 속성을 재정의 하면 속성의 값이 덮어쓰기 되어버린다는 점이다. 개발자가 객체의 모든 속성을 알고 있기 어렵고, 협업을 하기 때문에 JS에서 객체의 속성이 덮어쓰기 될 위험은 항상 존재한다.

 

const arr = [1,2,3,4,5];
const length = Symbol('length'); // Symbol Type 변수 length 선언
arr[length] = 10; // arr에 변수 length를 이용하여 property 추가

console.log(arr.length); // output: 5
console.log(arr[length]); // output: 10

  지금까지 객체 속성(property)의 키는 문자열만 가능한 것으로 알려졌지만, ES6 이후 심볼도 객체 속성의 키로 사용할 수 있다. 위 코드처럼 심볼 타입인 키를 갖는 객체 속성을 추가할 수 있다. 심볼로 생성한 값은 유일무이하므로, 객체의 기존 속성이 수정될 위험 없이 객체에 새로운 속성을 추가할 수 있다.

 

arr 객체의 형태

  Symbol을 이용하여 속성이 추가된 배열 객체는 위와 같은 형태이다.

 

2. Symbol의 특징

2-1. 생성

const x = Symbol();
console.log(typeof x); // output: symbol

  심볼 타입의 변수는 Symbol()이라는 함수를 통해 생성할 수 있다. 생성 시 new 키워드를 사용하지 않으며, new를 사용하면 TypeError가 발생한다. 즉, Symbol Wrapper 객체를 생성하지 않고, 항상 심볼 값(primitive value)만 생성 가능하다.

 

const x1 = Symbol();
const x2 = Symbol('x');

console.log(x1.toString()); // output: symbol()
console.log(x2.toString()); // output: symbol(x)

  심볼 생성 시, description이라는 인자를 넘길 수 있다. description은 심볼 값에 대한 설명이다. description 인자는 선택적으로 넘길 수 있으며, 값이 심볼 생성에 큰 영향을 주지는 않는다. 다만, 심볼을 명시적으로 문자열로 변환했을 때 description 인자 값이 함께 출력되므로 디버깅 용으로 사용할 수 있다.

 

const x1 = Symbol('x');
const x2 = Symbol('x');

console.log(x1 === x2); // output: false

  Symbol()은 항상 고유한 심볼 값을 리턴한다. 즉, 호출될 때마다 새로운 고유 심볼 값을 생성하여 리턴하는 것이다. 이 때문에 심볼을 객체 property key로 사용할 때, 이름 충돌이 발생하지 않는 것이다.

 

 

2-2. 문자열 변환

const x = Symbol('x');

console.log('var is ' + x); // TypeError : Cannot convert a Symbol value to a string
console.log(`var is ${x}`); // TypeError : Cannot convert a Symbol value to a string
console.log(`var is ${x.toString()}`); // output : var is Symbol(x)

  심볼은 암시적인 문자열 변환이 불가능하다. 즉, 문자열과 심볼을 이어 붙이기 위해선 toString(), new String()을 사용하여 명시적으로 변환해주어야 한다.

 

2-3. share Symbol

const x1 = Symbol.for('x');
const x2 = Symbol.for('x');
const x3 = Symbol('x');

console.log(x1 === x2); // true
console.log(x1 === x3); // false

  Symbol.for() 메서드를 사용하면 전역 심볼 레지스트리를 이용하여 심볼을 공유할 수 있다. Symbol.for('x')라는 뜻은 'x'라는 키를 갖는 심볼을 새롭게 생성하거나, 이미 존재하는 경우 해당 심볼을 리턴하라는 의미이다. 따라서 위 코드에서 x1에는 새롭게 생성된 심볼이, x2에는 x1과 같은 심볼이 리턴된다.

 

const x1 = Symbol.for('x');
const x2 = Symbol.for('x');
const x3 = Symbol('x');

Symbol.keyFor(x1); // 'x'
Symbol.keyFor(x3); // undefined

  Symbol.keyFor() 메서드를 사용하면, 해당 심볼이 전역 심볼 레지스트리에 어떤 키로 등록되어있는지 확인할 수 있다. 등록되지 않은 경우(= Symbol.for()로 생성하지 않은 심볼)는 undefined가 리턴된다. 

 

 

3. 객체 속성 키 Symbol의 특징

const sumOfAngle = Symbol('sumOfAngle');

const triangle = {
  name: '삼각형',
  color: 'red',
  [sumOfAngle]: 180
}

  객체에 심볼을 이용하여 새로운 객체 속성을 추가하였을 때, 새롭게 추가된 객체 속성은 어떤 특징이 있는지 알아보자.

 

3-1. get Keys without Symbol

Object.keys(triangle); // ['name', 'color']
for (const pr in triangle) { console.log(pr); }; // 'name' 'color'

  심볼 타입을 키로 갖는 객체 속성은 Object.keys() 나, for-in 문법으로 접근할 수 없다. 즉, 속성을 은닉할 수 있다.

 

3-2. get Symbols

Object.getOwnPropertySymbols(triangle); // [Symbol(sumOfAngle)]
Reflect.ownKeys(triangle); // ['name', 'color', Symbol(sumOfAngle)]

  심볼 타입을 키로 갖는 객체 속성은 Object.getOwnPropertySymbols()나, Reflect.ownKeys()로 접근 가능하다.

 

 

4. Symbol 활용

4-1. 객체 프로퍼티 은닉 및 확장

String.prototype[Symbol.for('getVowel')] = function (target) {
  return target.match(/[aeiou]/g);
}

  내장 객체에 사용자 정의 프로퍼티를 추가해야 할 때 혹은 객체에 은닉되어야 하는 속성을 추가할 때 유용하다. 내장 객체에 심볼을 이용하여 속성을 추가하면, 추후 내장 객체에 새로운 속성들이 추가되어도 이름이 충돌되지 않는다.

 

4-2. Enum

export const meta = {
  inspectable: Symbol('inspectable'),
  inspected: Symbol('inspected'),
  name: Symbol('name'),
  preview_long: Symbol('preview_long'),
  preview_short: Symbol('preview_short'),
  readonly: Symbol('readonly'),
  size: Symbol('size'),
  type: Symbol('type'),
  unserializable: Symbol('unserializable'),
};

  심볼은 전역에서 유일한 값을 가지므로, enum을 구현하기 위해 사용되기도 한다.

 


 

MDN : https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Symbol

Symbol : https://javascript.info/symbol

Symbol을 사용하는 이유는 뭘까 : https://another-light.tistory.com/105

'Web > [JS] Common' 카테고리의 다른 글

Wrapper Object  (0) 2021.11.21
Generator Function - function*  (0) 2021.11.11
Compile in V8  (0) 2021.10.23
This Binding 유형  (0) 2021.10.19
Call By Value? Call By Reference?  (0) 2021.09.04
Comments