ES6 Destructuring assignment

24 Mar 2016

1. 글에 대해

  • 모든 결과는 Chrome 브라우저(ver 49)를 통해 테스트된 결과입니다.

2. Destructuring assignment(해체 할당)이란?

  • 해체 할당은, 배열 또는 객체 리터럴과 유사한 문법으로, 변수에 값을 할당하는 JS 표현식중 하나이다.

3. Array destructing assignment(배열 해체 할당)

  • 배열 해체 할당을 통해, iterator 객체의 요소값을, 변수에 할당시킬 수 있다.

    • Array in ES5

        {
          // ES5 에서, 배열 객체 요소를 변수에 할당시키는 기본적인 방법이다.
          var arr = [1, 2];
          
          var x = arr[0];
          var y = arr[1];
          
          console.log(x, y); // 1 2
        }
          
      
    • Iterator in ES6

      • 기본적인 할당 방법

          {
            let arr = [1, 2];
                    
            // (블록 스코프)변수 선언과, 해체 할당을 한줄로 표현할 수 있다.
            let [x, y] = arr;
                    
            console.log(x, y); // 1 2
                    
            // 변수 선언이 생략된 x, y 속성은, 실행 코드 처리 시, globalEC.VO 의 속성으로 추가된다.
            [_x, _y] = arr;
                    
            // globalEC.VO.x, globalEC.VO.y
            console.log(this._x, this._y, window._x, window._y); // 1 2 1 2
          }
        
      • 변수 할당을 건너뛰는 방법

          {
            let arr = [1, 2, 3, 4];
        
            // 아래와 같은 표현식을 통해, 변수 할당을 건너뛸 수 있다.
            let [x, , , z] = arr;
        
            console.log(x, z); // 1 4
          }
        
      • 나머지 연산자를 통한 해체 할당

        ```javascript
        {
            let arr = [1, 2, 3];
        
            // y 변수에는, (할당될)배열 객체의 나머지 요소(2, 3)가 포함된 새로운 배열 객체([2, 3])가 할당된다.
            let [x, ...y] = arr;
        
            console.log(x, y); // 1 [2, 3]
        
            let [_x, ..._y] = [1];
        
            // _y 변수에는, (할당될)배열 객체의 나머지 요소가 존재하지 않으므로, 빈 배열 객체가 할당된다.
            console.log(_x, _y); // 1, []
        }
        ```
        
        • (할당될)변수의 기본값을 지정할 수 있다.

            {
                let arr = [1];
          
                // y 변수에 기본값 2 를 지정한다.
                let [x, y = 2] = arr;
          
                // y 변수에 기본값 2 가 할당된다.
                console.log(x, y); // 1 2
          
                // _x 변수에 기본값 1 을 지정한다.
                let [_x = 1] = [undefined];
          
                // _x 변수에 기본값 1 이 할당된다.
                console.log(_x); // 1
          
                // 함수 표현식을 기본값으로 사용할 수 있다.
                let [__x = (() => {
                    return 1;
                })()] = [];
          
                // __x 변수에 함수 표현식을 통해 반환받은 기본값 1이 할당된다.
                console.log(__x); // 1
          
                // ___x, ___y 변수에 각각 기본값 3, ___x 변수를 지정한다.
                let [___x = 3, ___y = ___x] = [];
          
                // ___x, ___y 변수에 각각 기본값 3, ___x 변수값이 할당된다.
                console.log(___x, ___y); // 3 3
          
                // ____x, ____y 변수에 각각 기본값 3, ____x 변수를 지정한다.
                let [____x = 3, ____y = ____x] = [7];
          
                // ____x, ____y 변수에 각각 배열 요소값 7, ____x 변수값이 할당된다.
                console.log(____x, ____y); // 7 7
            }
          
        • 중첩 배열에 대한, 해체 할당

           {
             // 중첩 배열을 통한 해체 할당
             let arr = [1, [3, 4, 5]];
          
             let [x, [y, ...z]] = arr;
          
             // z 변수에는 (할당될)변수 객체의 나머지 요소(4, 5)가 포함된 새로운 배열[4, 5]이 할당된다.
             console.log(x, y, z); // 1 3 [4, 5]
          
             let [_x, ...[_y, _z]] = [1, 2, 3];
          
             // (나머지 연산자의)피 연산자는 꼭 변수가 아니여도 된다.
             // 즉 나머지 연산자를 통해, 할당된 피연산자를 한번 더, 해체 할당하면 아래와 같은 결과가 반환된다.
             console.log(_x, _y, _z); // 1 2 3
           }
          
        • 함수 인자값을 통한, 해체 할당

           {
          
               let A = ([x, y = 2]) => {
          
                   // y 변수에는 지정된 기본값인 2가 할당된다.
                   console.log(x, y); // 1 2
               };
          
               A([1]);
          
               let B = ([x, y] = [1, 2]) => {
          
                   // x, y 변수에는 지정된 기본값인 1, 2 가 할당된다.
                   console.log(x, y); // 1 2
               };
          
               B();
          
               let C = ([x = 1, y = 2] = []) => {
                   console.log(x, y);
               };
          
               // 전달된 인자값이 없는경우, 그에 대한 기본값인 "빈 배열" 객체가 할당되며,
               // 또 그 배열에 대한 기본값인 x = 1, y = 2 가 다시 할당되게된다.
               C(); // 1 2
          
               // 지정된 기본값인 1, 2 가 할당된다.
               C([]); // 1 2
          
               // 전달된 인자값이 할당된다.
               C([3, 4]); // 3 4
          
          
               // block scope
               let x = 'outer';
          
               let D = function(_x = x) {
          
                   // x 변수 선언 후, 2를 할당한다
                   let x = 'inner';
                   console.log(_x); // outer
               }
          
               // 전달된 인자값이 없는 경우, 지정된 기본값인 x 변수가 할당된다.
               D();
          
               // args 변수에는, 전달된 인자값이 모두 포함된 새로운 배열이 할당된다.
               let E = function(...args) {
          
                   // x, y 변수에 할당한다.
                   let [x, y] = args;
          
                   console.log(x, y); // 1 2
               }
          
               E(1, 2);
           }
          
          
      • 그 밖의 표현식

        • 문자열 할당

            {
          
                // 문자열이 할당될 경우에는, 해당 문자열을 암묵적으로 iterator 객체로 변환한다.
                let [x, y, z] = 'xyz';
          
                console.log(x, y, z); // x y z
          
                // 아래 코드는 동일한 결과를 반환한다.
                // let [_x, _y, _z] = new String('xyz')[Symbol.iterator]();
            }
          
          
        • new Set([])

            {
                // 생성된 set 객체를 통해, iterator 객체를 할당한다.
                let [__x, __y] = new Set([1, 2]);
          
                console.log(__x, __y); // 1 2
          
                // let [__x, __y] = new Set([1, 2]).values();
            }
          
        • generator 할당

            {
                // generator 를 선언한다.
                function* $$() {
                    for (let i = 1; ; i++) {
                        yield i;
                    }
                }
          
                // 생성된 generator 를 할당한다.
                let [x, y, z] = $$();
          
                console.log(x, y, z); // 1 2 3
          
                // 객체 내부에 생성된 generator 를 할당한다.
                let [_x, _y] = {
                    // generator 생성한다
                    * [Symbol.iterator]() {
                        for (let i = 1; i < 10; i++){
                            yield i;
                        }
                    }
                };
          
                console.log(_x, _y); // 1 2
          
                // iterator 인터페이스를 구현한, iterator 객체를 할당한다.
                let [__x, __y] = {
                    i: 0,
                    [Symbol.iterator]() {
                        // iterator 객체를 반환
                        return this;
                    },
                    next(){
                        return {value: ++this.i, done: this.i > 10};
                    }
                };
          
                console.log(__x, __y); // 1 2
            }
          
        • ETC

            {
          
                // 정규식을 통해, 반환된 iterator 객체를 할당한다.
                let [, x, y, z] = /(\d+)\/*(\d+)\/*(\d+)/.exec('2016/03/01');
                console.log(x, y, z); // 2016 03 01
          
          
                // map 객체를 생성한다.
                let m = new Map([
                    [1, 'a'],
                    [2, 'b'],
                    [3, 'c']
                ]);
          
                // map 객체를 통해, 새로운 배열 객체를 생성한다.
                let _m = new Map([...m].map(([k, v]) => {
                    return [k * 2, '_' + v];
                }));
          
          
                let urls = [
                    'http://example.com/foo.html',
                    'http://example.com/bar.html',
                    'http://example.com/baz.html'
                ];
          
                // Promise.all 메서드를 통해, 전달된 url 집합을 할당한다.
                Promise.all(urls.map((url) => {
                    return url;
                })).then(([url1 = top.window.location.href, url2 = top.window.location.href, url3 = top.window.location.href]) => {
          
                    // 전달받은 배열 객체(['http://example.com/foo.html', 'http://example.com/bar.html', 'http://example.com/baz.html'])가 해체 할당된다.
                    console.log(url1, url2, url3);
                });
            }
          

4. Object destructing assignment(객체 해체 할당)

  • 객체 해체 할당을 통해, 객체 속성값을, 변수에 할당시킬 수 있다.

    - Object in <span style="color:#c11f1f">ES5</span>
      
        ```javascript
          
        {
            // ES5 에서, 객체 속성을 변수에 할당시키는 기본적인 방법이다.
            let o = {x: 1, y: 2};
              
            let x = o.x;
            let y = o.y;
      
            console.log(x, y); // 1 2
        }                    
        ```                                           
                     
    - Object in <span style="color:#c11f1f">ES6</span>
          
        - **기본적인** 할당 방법
          
            ```javascript
            {
                let o = {x: 1, y: 2};
          
                // (블록 스코프)변수 선언과, 해체 할당을 한줄로 표현할 수 있다.
                let {x, y} = o;
          
                // (할당될)변수 이름을 객체 속성 이름과 다르게 생성하고 싶을때에는, 아래와 같은 표현식을 사용할 수 있다.
                let {x: _x, y: _y} = o;
          
                console.log(x, y, _x, _y); // 1 2 1 2
            }
            ```   
                                              
        - (할당될)변수의 **기본값**을 지정할 수 있다.
          
            ```javascript
            {
                let o = {x: 1};
          
                // y 변수에 기본값 2 를 지정한다.
                let {x, y = 2} = o;
          
                console.log(x, y); // 1 2
          
                // _y 변수에 기본값 2 를 지정한다.
                let {x: _x, y: _y = 2} = o;
          
                console.log(_x, _y); // 1 2
          
          
                // 배열 요소가 존재하지 않을 경우, 그에 대한 기본값인 "빈 객체"가 할당되며,
                // 또 그 객체에 대한 기본값인 __y = 2 가 다시 할당된다.
                let [{x: __x, y: __y = 2} = {}] = [];
          
                console.log(__x, __y); // undefined 2
          
          
                // 배열 요소가 존재하지 않을 경우, 그에 대한 기본값인 "빈 객체"가 할당되며,
                // 또 그 객체에 대한 기본값인 ___x = {x: 1}, ___y = 2 가 다시 할당된다.
                let [{x: ___x, y: ___y = 2} = {x: 1}] = [];
          
                console.log(___x, ___y); // 1 2
            }
            ```
                                                               
        -  **중첩 객체**에 대한, 해체 할당
          
            ```javascript
            {
                // 중첩된 객체를 생성한다.
                let o = {x: 1, y: {_x: 2, _y: {__x: 3}}};
                  
                // 중첩된 객체가 해체 할당된다.
                let {x, y: {_x, _y: {__x}}} = o;
          
                console.log(x, _x, __x); // 1 2 3
            }
            ```  
                                                                           
        -  **함수 인자값**을 통한, 해체 할당
          
            ```javascript
            {
                let A = ({x = 1, y = 2}) => {
                    console.log(x, y); // 1 2
                };
          
                // y 변수에는 기본값인 2가 할당된다.
                A({x: 1});
          
                let B = ({x, y} = {x: 1, y: 2}) => {
                    console.log(x, y); // 1 2
                };
          
                // 인자값이 전달되지않은 경우에도, 기본값인 {x: 1, y: 2} 가 할당된다.
                B();
          
                let C = ({x = 1, y = 2} = {}) => {
                    console.log(x, y); // 1 2
                };
          
                // 인자값이 전달되지않은 경우에는, 그에 대한 기본값인 빈 객체가 할당되며,
                // 또 그 객체에 대한 기본값인 x = 1, y = 2 가 다시 할당된다.
                C();
                  
              // 해체 할당을 통해 이와 같은 패턴이 적용될듯 하다.
              function ajax({url = top.location.href, method = 'GET', headers = {}} = {}){
        
                  return {
                      url: url,
                      method: method,
                      headers: headers
                  };
              };
        
              console.log(ajax()); // {url: "http://localhost:8080/sourceTest/es6/destructuring_assignment.html", method: "GET", headers: Object}
                
              console.log(ajax({url: 'myUrl', method: 'POST', headers: {contentType: ''}})); // {url: "myUrl", method: "POST", headers: Object}                  
            }
            ```                                                                             
                       
    - 그 밖의 표현식     
                                     
        - (할당)패턴 없이, 값을 할당할 경우에는 그 값을 **객체**로 변환 후, 해당 속성값을 할당시킨다
          
            ```javascript
            {
          
                let {length: x} = [1] // [].length
                console.log(x); // 1
          
                let {toString: xx} = {} // {}.toString
                console.log(xx); // toString function object
                  
                // 할당될 값에 (할당)패턴이 적용된 경우...
                let {toString: _xx} = {toString: 1} // {}.toString
                console.log(_xx); // 1                  
          
                let {length: xxx} = 'mohwa'; // === new String('mohwa').length
                console.log(xxx); // 5
          
                let {toString: xxxx} = 'mohwa'; // === new String('mohwa').toString
                console.log(xxxx); // toString function object
          
                let {toFixed: xxxxx} = 1; // new Number(1).toFixed
                console.log(xxxxx); // toFixed function object
          
                let {valueOf: xxxxxx} = true; // new Boolean(true).valueOf
                console.log(xxxxxx); // valueOf function object
          
                let {length: xxxxxxx} = function(x){}; // function(x){}.length
                console.log(xxxxxxx); // 1
          
                let {x: xxxxxxxx} = 'mohwa'; // new String('mohwa').xx
                console.log(xxxxxxxx); // undefined
          
          
                // undefined 와 null 값은 예외가 발생한다.
          
                try{
                    let {toString: x} = undefined; // === undefined.toString
                }
                catch(e){
                    console.log(e.message); // Cannot match against 'undefined' or 'null'.
                }
          
                try{
                    let {toString: x} = null; // === null.toString
                }
                catch(e){
                    console.log(e.message); // Cannot match against 'undefined' or 'null'.
                }
          
            }
            ```
              
        - **Symbol** 을 통한 해체 할당
          
            ```javascript
            {
                const k = Symbol();
                let o = { [k]: 1 };
          
                let {[k]: x} = o;
          
                console.log(x); // 1
            }        
            ```                             
    

관련 URL

comments powered by Disqus