ES6 Symbols: Drumroll Please!


원문
Paul Shannon, https://www.sitepen.com/blog/es6-symbols-drumroll-please/

심볼(Symbols)은 ES6에서 소개된 새롭고 유일한 원시(primitive) 타입이다. 이들은 자바스크립트 이전 버전에서 작성된 코드와 역방향 호환성을 유지하면서, 객체의 기능을 확장하는 문제를 해결하기 위해 언어에 추가됐다. 그들은 부가적으로 개발자들이 새롭고 흥미로운 방법으로 언어 동작에 영향을 미칠 수 있는 기능을 제공한다. 이 아티클에서는 심볼의 개념 소개와 목적에 대한 설명, 그리고 현재 심볼을 사용할 수 있는 가장 일반적인 방법을 연결 지어 보여주겠다.

상세한 내용에 들어가기 전에, 새로운 심볼이 어떻게 생성되는지부터 보자.

const mySymbol = Symbol();

원시 심볼은 내장 팩토리(factory) 함수를 사용해 생성된다. 팩토리는 기본 요소 구축을 위한 자바스크립트를 통해 사용된다. 예를 들어, 새로운 DOM 엘리먼트(element) 생성은 document.createElement()를 통해 완성된다. 이러한 방식으로 생성된 심볼은 “사용자 정의 심볼(custom symbols)”이라고 한다.

Symbol 객체는 “잘 알려진 심볼(well-known symbols)"이라는 자바스크립가 제공하는 명명된 심볼을 갖는다. 이 심볼들은 자바스크립트에 의해 작성되었으며 상호작용과 근본적인 자바스크립트 코드의 동작을 수정하는데 사용된다. 잘 알려진 심볼(well-known symbols) 중 가장 일반적인 심볼은 Symbol.iterator인데, 이는 객체의 값 이상의 반복의 의미를 추가하는데 사용한다. 또한 심볼은 객체를 정규 표현식처럼 사용할 수 있게 하는 것과 타입이 자바스크립트에 보고하는 방법을 바꾸는 것(예를 들면 typeof를 통해) 그리고 구성하고 사용자 정의 객체를 변환하는 방법을 허용한다.

사용할 수 있는 새롭고 유일한 원시 타입과 함께 자바스크립트는 이전에 사용된 이름과의 충돌에 대한 걱정 없이 객체 기능에 추가 할 문자열과 동일한 속성 명의 심볼을 사용할 수 있다. 이것은 중요한 이유는, ECMAScript 스펙이 Symbol.iterator 대신 “iterator” 문자열을 선택했다면 속성명으로 “Iterator” 문자열을 사용하는 오래된 코드에서 ECMAScript 6 문맥을 사용할 때 의도하지 않은 결과를 가져올 수 있었기 때문이다.

심볼은 이름 충돌 문제를 해결했다. 그들은 고유하기 때문에, 이제까지 같은 값을 공유하지 않았다.

Symbol() !== Symbol()

이것은 자바스크립트가 이전에 작성된 코드와 충돌 없이 잘 알려진 심볼 추가하여 지속적으로 기능을 추가할 수 있다는 것을 의미한다.

심볼로 무엇을 할 수 있나?

심볼은 개발자가 확장하는 것을 허용한다 그리고 이것은 자바스크립트 엔진의 행동에 영향을 미칠 수 있다. 예를 들어. 잘 알려진 심볼인 Symbol.iterator(또는 @@iterator 참조 값)를 사용하여, 객체로 for...of나 펼쳐짐(spread) 연산자를 사용하는 경우, 제공된 데이터가 무엇인지에 대해 설명할 수 있다.

class Data {
    constructor(... rest) {
        this._data = rest;
    }
    *[Symbol.iterator]() {
        for (let item of this._data) {
            yield item;
        }
    }
}
 
console.log([... new Data(1, 2, 3)]);  // outputs: [ 1, 2, 3 ]

이 예제에서 자바스크립트 엔진은 @@iterator 를 구현한 사용자 정의 객체를 배열 리터럴 구축에 사용되는 값을 생성하기 위한 내부 루틴의 일부로 사용한다.

자바스크립트 언어의 주요한 작동 방식을 변경하는 심볼을 사용하는 경우 행동 변화는 더욱 분명하다. 예를 들어, @@toStringTag는 목적을 설명하는 방법을 정의한 심볼이다.

let arraylike = {
    0: 'zero',
    1: 'one',
    length: 2,
    [Symbol.toStringTag]: 'Array',
    *[Symbol.iterator]() {
        for (let i = 0; i < this.length; i++) {
            yield this[i];
        }
    }
}
 
console.log(arraylike.toString());  // [object Array]

@@replace는 정규 표현식을 위해 예약된 이전 문맥에서 행동하기 위한 객체를 허용한다.

const Summary = {
    maxLength: 35,
    defaultEnding: '...',
    [Symbol.replace](str, replacement) {
        if (str.length > this.maxLength) {
            replacement = replacement || this.defaultEnding;
            const length = this.maxLength - replacement.length;
            return str.substring(0, length) + replacement;
        }
        return str;
    }
};
 
const sentence = 
    'This sentence is way too long and will be summarized!';
 
// prints: This sentence is way too long an...
console.log(sentence.replace(Summary));

개발자들에게 언어 수준의 기능을 오버라이드(override) 할 수 있는 권한을 주는 것은 이전에 브라우저가 확장 가능한 웹 선언에서 핵심 구성요소이기 위해 접근 가능했을 때에나 가능했다. 그것은 더 많은 실험이 가능하게 하며 개발자들은 이전에 손이 닿지 않았던 라이브러리 주위 저레벨(low-level) 기능을 구축하게 한다.

심볼 사용하기

심볼은 엣지(Edge) 12로 시작하는 모든 최신 브라우저에서 기본적으로 유효하다. 그러나 Symbol.iterator과 같은 잘 알려진 많은 심볼(well-known symbols)들은 모든 브라우저에 구현되어 있지는 않다. 이것은 심볼을 지원하는 최신 브라우저들도 많은 잘 열려진 심볼을 위한 폴리필(pollyfill)이 필요하다는 것을 의미한다. 그것은 instanceof와 상호작용하는 @@hasInstance 나 값을 위해 객체 타입을 변경하는데 사용된 @@toPrimitive와 같이 몇 가지 잘 알려진 심볼의 폴리필은 문법이나 연산자로 부터 온 행동을 복제를 할 수 없다고 알리기 위해 중요하다.

기본(native) 심볼 타입이 없는 ES5 브라우저는 추가적인 검토가 필요하다. 먼저, 심볼이 원시 타입이기 때문에, 폴리필은 typeof 검사와 Symbol()이 문자열을 반환하는 것을 올바르게 복제할 수 없다. 또한, in 연산자는 폴리필된 심볼을 반환할 것이다. 왜냐하면 그들 하부는 단지 문자열이기 때문이다. 마지막으로 Symbol.for()와 Symbol.keyFor는 상호 영역을 지원하지 않는다.

타입스크립트(TypeScript) 사용자의 상황은 더 복잡해진다. 타입스크립트는 ES6 코드를 에밋할 때 심볼을 지원한다. 반면에 ES5로 에밋할 때에는 심볼 타이핑을 제공하지 않으며, 심볼 사용은 에러로 보고될 것이다. 타입스크립트 개발자들은 다음 세 가지 중에 한가지 방법으로 이 문제를 해결할 수 있다.

  1. dojo/core나 ES5 문법으로 ES6 기능을 지원하는 심(shims)과 함께 다른 라이브러리를 사용한다.
  2. ES6를 위한 타입스크립트 변환 체인을 구축하여 생성하고 ES5를 변환하기 위한 바벨(Babel)을 사용한다.
  3. 심볼 타입 대신 다른 타입을 사용한다.

각각의 해결 방법은 ES5 환경에서 심볼을 지원해야 하기 때문에 장단을 모두 갖고 있다. 우리는 멀티 플랫폼을 대상으로 하는 동안 타입과 일관성을 유지하기 위해 가장 좋은 방법을 제안하고 ES5 문법으로 ES6 기능을 감싸서 사용하는 심 라이브러리 사용을 신뢰한다. 또한 타입스크립트 로드맵에서 조건부 컴파일세분화된 타켓팅 기능 계획을 통해 이 이슈를 도와줄 계획을 갖고 있다.

이러한 주의 사항이 부담스럽게 들릴지도 모르겠지만, 그 문제들 중 많은 부분은 바벨(Babel)과 core.js와 같은 좋은 폴리필과 같은 변환기를 사용하고 위에서 얘기한 예외의 인식을 통해 해결할 수 있다. 이 도구들과 함께 엔지니어들은 ECMAScript6에서 제공하는 현대적인 개념과 문법의 장점을 취하고 보다 효율적이고 쉽게 읽을 수 있는 코드 작성을 시작할 수 있다.

더 알아보기

우리는 ES6 & 엔터프라이즈 개발을 위한 타입스크립트 워크샵에서 심볼과 ES6를 위한 많은 유용한 추가 기능에 대해 제공하고 있다. 우리는 ES6와 타입스크립트의 기초를 배우는 것이 그 어느 때 보다 중요하다고 믿는다. 거의 20년 만에 언어에 대한 첫 번째 실질적인 변화와 함께, 지금은 웹 어플리에이션을 만들기 위해 기본적인 언어를 위한 변화를 효율적으로 활용하는 방법을 배울 수 있는 시간이다.

우리는 또한 우리의 자바스크립트 지원 계획을 통해 ES6와 타입스크립트를 배울 때, 도움을 제공한다. 그리고 언어에 대한 많은 변화와 함께 당신의 어플리케이션의 아키텍처 접근 방식을 개선하기 위한 여러 가지 방법이 있다. 어플리케이션 아키텍처를 논의하기 위해, 그리고 우리가 도울 수 있는 방법에 대해 배우기 위해 우리에게 연락하기 바란다.


강지웅, FE Development Lab2016.05.02Back to list