on
Symbol 데이터 타입
Symbol 데이터 타입
728x90
<심볼(Symbol) 타입>
1997년 탄생한 이래, 자바스크립트는 본래 6가지의 데이터 타입만을 가지고 있었다. 원시 타입(문자열, 불리언, 숫자, null, undefined)과 객체(Object) 타입이다.
심볼(Symbol)은 ES6가 도입되면서 함께 등장한 7번째 데이터 타입이며, 원시 타입에 해당되는 데이터 타입이다.
심볼은 변경 불가능한 원시 타입의 데이터 타입이며, 다른 값과 절대 중복되지 않는 고유한 값의 데이터 타입이다.
const symbol1 = Symbol('symbol') const symbol2 = Symbol('symbol') console.log(symbol1 === symbol2) // false
또한 심볼 데이터 타입에 원시 데이터를 저장해도, 자바스크립트는 이를 원시 데이터로 간주하지 않는다. 따라서 원시 데이터 타입과 심볼 데이터를 어떤 식으로든 결합시키면 오류가 발생한다.
즉, 심볼 타입은 암묵적 형 변환이 일어나지 않으나, 예외적으로 불리언 타입에 대해서는 형 변환이 일어난다.
const symbol1 = Symbol(); console.log(symbol1 + '') // TypeError console.log(+symbol1) // TypeError console.log(!!symbol1). // true
심볼은 이러한 특성 때문에, 오브젝트형 데이터 타입의 프로퍼티를 만드는 데 주로 사용된다. 이것이 뜻하는 바에 대해서는 아래에서 좀 더 자세하게 다루어 보려고 한다.
<심볼의 용도>
우리가 객체를 다룰 때, 프로퍼티를 설정하는 데에 많은 자원을 할애하곤 한다. 프로퍼티는 key와 value 쌍으로 이루어져 있고, 키에 해당되는 부분은 모두 문자열로 이루어져 있다.
(간혹 키 부분에 숫자를 입력해도 이상이 없는 것은 객체 내부에서 이 숫자를 문자로 변환 하기 때문이다.)
앞서 말한 것과 같이, 심볼 타입이 새롭게 등장하면서 이 심볼 타입 역시 프로퍼티 키로 사용할 수 있게 되었다.
const obj = {}; const sym1 = Symbol(); const sym2 = Symbol('foo'); const sym3 = Symbol('foo'); obj[sym1] = 'propertyValue1'; obj[sym2] = 'propertyValue2'; obj[sym3] = 'propertyValue3'; // no conflict with sym2 console.log(obj); // {Symbol(): 'propertyValue1', Symbol(foo): 'propertyValue2', Symbol(foo): 'propertyValue3'} console.log(obj[sym1]); // propertyValue1 console.log(obj[sym2]); // propertyValue2 console.log(obj[sym3]); // propertyValue3
심볼을 사용할 때에는 우리가 직접 심볼 타입을 선언하는 방법도 있지만, 자바스크립트에 내장된 심볼을 사용하는 것도 가능하다. 이를 내장 심볼이라고 한다.
이들은 자바스크립트 엔진 내에 이미 생성되어 일종의 상수로 작용하고 있고, 심볼 생성 함수인 Symbol() 역시 객체에 해당하기 때문에, 이러한 내장 심볼들을 일종의 프로퍼티로 가지고 있을 수 있다.
내장 심볼의 가장 대표적인 예는 Symbol.iterator로, 자바스크립트 엔진은 이 심볼을 프로퍼티로 가지고 있는 객체를 이터러블한 객체라고 받아 들인다.
Array.prototype[Symbol.iterator]; String.prototype[Symbol.iterator]; Map.prototype[Symbol.iterator]; Set.prototype[Symbol.iterator]; arguments[Symbol.iterator]; NodeList.prototype[Symbol.iterator]; HTMLCollection.prototype[Symbol.iterator];
<알아두어야 할 심볼 메서드>
심볼과 관련하여, 자바스크립트 엔진에는 전역 심볼 레지스트리(Global Symbol Registry)라는 개념이 존재한다. 전역 심볼 레지스트리란 심볼들이 저장되는 전역 공간을 의미하는 것이며, 여러 모듈들이 하나의 심볼을 공유하기 위한 용도로 존재한다.
(단, 일반적인 심볼 생성 함수로 만든 심볼은 이 레지스트리에 등록되지 않는다.)
이 때 활용하는 것이 Symbol.for 메서드이다. 원래 심볼 생성 함수에는 문자열을 인자로 넣을 수 있는데, Symbol.for 메서드를 활용하여 객체의 프로퍼티들이 같은 심볼을 공유하도록 할 수 있다.
Symbol.for 메서드는, 인자로 받은 문자열을 전역 심볼 레지스트리에서 검색해서, 일치하는 문자열을 찾으면 기존의 심볼을 반환한다.
만약 일치하는 문자열이 없을 경우, Symbol()와 같이 새로운 심볼을 생성하는 식이다.
const sym1 = Symbol.for('foo'); // Cretate symbol const sym2 = Symbol.for('foo'); // Reuse symbol console.log(sym1 === sym2); // true
Symbol.keyFor() 메서드는 심볼을 생성하지는 않고, 인자로 전달받은 심볼을 전역 심볼 레지스트리에서 찾고, 그 심볼의 키를 반환하고, 탐색에 실패한다면 undefined를 반환한다.
다음의 코드 블럭을 통해 더욱 쉽게 이해할 수 있다.
const unsharedSym = Symbol('foo'); const symKey1 = Symbol.keyFor(unsharedSym); console.log(symKey1); // undefined const sharedSym = Symbol.for('foo'); const symKey2 = Symbol.keyFor(sharedSym); console.log(symKey2); // foo
위의 코드 블럭에서, unsharedSym은 일반 심볼 생성 함수로 만들었기 때문에, 전역 심볼 레지스트리에 등록되지 않는다. 따라서 Symbol.keyFor 메서드를 사용했을 때 undefined를 반환하는 것이다.
<프로퍼티 은닉>
일반적으로 객체 내의 프로퍼티는 for ... in 문을 사용하여 검색할 수 있다. 하지만, 기본적으로 JavaScript가 제공하는 for ... in 문법에서 키가 심볼인 프로퍼티들은 열거되지 않는다.
따라서 심볼을 사용하면 외부에 노출할 필요가 없는 프로퍼티를 은닉시키는 효과를 얻을 수 있다.
개발 단계에서 키가 심볼인 프로퍼티를 확인해야 한다면 Object.getOwnPropertySymbols() 메서드를 사용할 수 있다.
const obj = {}; obj[Symbol('a')] = 'a'; obj[Symbol.for('b')] = 'b'; obj['c'] = 'c'; obj.d = 'd'; for (const propertyKey in obj) { console.log(propertyKey); // logs 'c' and 'd' }
또한, 객체를 JSON으로 만들 때도 키가 심볼인 프로퍼티들은 무시한다. 따라서 JSON.stringify() 메서드를 호출 할 때도 심볼 타입이 포함되어 있다면 유의해야 한다.
728x90
from http://oaat9309.tistory.com/46 by ccl(A) rewrite - 2021-12-19 11:28:15