ES6의 낯선 문법 (destructuring)

Destructuring

ES6: Use Destructuring Assignment to Assign Variables from Objects

우리는 앞서 spread operator로 어레이의 내용을 효과적으로 spread 혹은 unpack 할수있는 방법을 봤습니다.

오브젝트로도 비슷하게 할수있습니다. Destructuring assignment 는 편하게 오브젝트에서 직접 값을 가져다 변수에 할당할 수 있는 특별한 문법입니다.

ES5에서는

var voxel = {x: 3.6, y: 7.4, z: 6.54 };
var x = voxel.x;                     // x = 3.6
var y = voxel.y;                     // y = 7.4
var z = voxel.z;                     // z = 6.54

ES6 destructuring syntax:

const { x, y, z } = voxel;        // x = 3.6, y = 7.4, z = 6.54

만약 voxel.x 를 a에, voxel.y 를 b에, voxel.z 를 c 로 바꿔 넣고 싶다면 이렇게 하면 됩니다.

const { x : a, y : b, z : c } = voxel;         // a = 3.6, b = 7.4, c = 6.54

You may read it as “get the field x and copy the value into a,” and so on.

ES6: Use Destructuring Assignment to Assign Variables from Nested Objects

We can similarly destructure nested objects into variables.

const a = {
  start: { x: 5, y: 6},
  end: { x: 6, y: -9 }
};
const { start : { x: startX, y: startY }} = a;
console.log(startX, startY); // 5, 6

a.start의 nested object a.start.x 를 startX로, a.start.y 를 startY 로 할당했다.

ES6: Use Destructuring Assignment to Assign Variables from Arrays

spread operator와 array destructuring의 한가지 중요한 차이는 spread operator는 어레이의 모든 내용을 unpack 해 컴마로 구분된 리스트로 만든다. 그 결과로, 어떤 얼리먼트를 변수에 할당할지 찝어낼 수 없음.

어레이를 destructuring 해보자

const [a, b] = [1, 2, 3, 4, 5, 6];
console.log(a, b);           // 1, 2

The variable ais assigned the first value of the array, and bis assigned the second value of the array. 변수 a는 어레이의 첫 값을 할당받고, b 는 어레이의 두번째 값을 할당받는다.

destructuring을 통해 우리가 원하는 어떤 인덱스의 값이라도 액세스 가능하다

const [a, b,,, c] = [1, 2, 3, 4, 5, 6];              // 변수 지정 없이 컴마를 넣어서 다음 인덱스로 넘어갈수있다
console.log(a, b, c);         // 1, 2, 5

디스트럭쳐링을 이용해 a 와 b의 값을 스왑하는 함수를 정의해보자 (문제)

let a = 8, b = 6;
(() => {
  "use strict";
  let arr = [a,b];         // a, b 값을 엘리먼트로 하는 어레이를 선언하고
  [b, a] = arr;             // 디스트럭쳐링을 통해 변수에 값을 재할당한다.
})();
console.log(a);      // should be 6
console.log(b);      // should be 8

ES6: Use Destructuring Assignment with the Rest Operator to Reassign Array Elements

어레이 디스트럭쳐링으로 액세스한 엘리먼트 외에 나머지 엘리먼트를 분리된 어레이에 모으고 싶을 수 있다. 결과는 Array.prototype.slice()와 비슷하다 :

const [a, b, ...arr] = [1, 2, 3, 4, 5, 7];
console.log(a, b);                   // 1, 2
console.log(arr);                    // [3, 4, 5, 7]

변수들 a, b는 어레이의 첫째, 둘째 엘리먼트를 가져가고, rest operator가 있기 때문에 arr 에는 나머지 엘리먼트들을 어레이 형태로 가져간다. ’rest 엘리먼트’ 는 list에서 마지막 변수일때만 바르게 동작한다. (남은걸 싸그리 긁어와 변수에 넣는 연산자를 이용하니까.) 따라서 원본 어레이에서 엘리먼트를 남기는 서브어레이를 만드는데는 사용할 수 없다.

source 어레이에서 첫 두 엘리먼트를 생략하고 나머지를 서브어레이로 출력하는 slice() 를 구현해보자

const source = [1,2,3,4,5,6,7,8,9,10];
function removeFirstTwo(list) {
  "use strict";
  const [,, ...arr] = list;       // 첫 두 엘리먼트를 버리기 위해 ,,를 찍고 나머지는 rest operator로 arr를 선언하며 할당한다
  return arr;
}
const arr = removeFirstTwo(source);
console.log(arr);                // should be [3,4,5,6,7,8,9,10]
console.log(source);         // should be [1,2,3,4,5,6,7,8,9,10];

ES6: Use Destructuring Assignment to Pass an Object as a Function’s Parameters

몇몇 경우에, 함수 인자로 들어간 오브젝트를 디스트럭쳐링 할 수 있다.

코드를 보자 :

const profileUpdate = (profileData) => {
  const { name, age, nationality, location } = profileData;
  // do something with these variables
}

함수에 인자로 전달된 오브젝트 profileData를 효과적으로 디스트럭쳐링 할 수 있다. This can also be done in-place: in-place 로 행해질 수 있다. ( in-line 말인가 )

const profileUpdate = ( { name, age, nationality, location } ) => {    // parameter 자리에 바로 넣어서 4개를 선언한다
  /* do something with these fields */
}

전체 오브젝트를 조작할 필요가 없게 해주는 장점이 있다; 필요한 필드만을 함수 안으로 복사한다.

const stats = {
  max: 56.78,
  standard_deviation: 4.34,
  min: -0.75,
  average: 35.85
};

const half = (function() {
  "use strict";
  return function half( {max, min} ) {         // 들어올 인자 오브젝트에서 max 키와 min 키만 인자로 받는다
    return (max + min) / 2.0;
  };
})();
console.log(stats); // should be object
console.log(half(stats)); // should be 28.015

(아래는 destructuring과 함께 유용하게 쓸 수 있는 오브젝트 리터럴 정의 방법이다.)

ES6: Write Concise Object Literal Declarations Using Simple Fields

object literal을 쉽게 정의할 수 있는 몇가지 지원이 추가됐다

const getMousePosition = (x, y) => ({
  x: x,
  y: y
});

getMousePosition 은 두개의 키를 포함한 오브젝트를 리턴하는 간단한 함수다. (ES6 에서 x: x를 적어야하는 쓸데없는 반복을 제거하는 문법적 편리함을 제공한다.)

x 를 한번만 쓰면 x: x 로 변환된다. (또는 동등한 어떤것으로 변환된다)

const getMousePosition = (x, y) => ({ x, y });

(원래 코드나 concise 코드나 리턴 오브젝트에 괄호 () 를 빼먹으면 에러가 난다.) (괄호가 없다면 오브젝트 리터럴이 아니라 선언하는 함수의 중괄호라고 여겨지는 모양이다)

(x, y) => { return {x, y} } // 됨
(x, y) => { ({ x, y }) } // 안됨

Destructuring는 배열과 객체에 패턴 매칭을 통한 데이터 바인딩을 제공합니다. Destructuring는 할당 실패에 유연하며, 실패 시 undefined 값이 자동할당 됩니다. 또한 foo["bar"]와 같이 객체의 속성 값도 자동으로 검색하여 바인딩해줍니다. https://jsdev.kr/t/es6/2944#destructuring

리액트에서 사용 예

import React, { Component } from "react";
import ReactDOM from "react-dom";

class Counter extends Component {
  constructor(props) {
    super(props);

    this.state = {
      currentValue: 0
    };
  }

  render() {
    return (
      <div>
        <button>Add</button>
        <div>{this.state.currentValue}</div>
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Counter />, rootElement);

Minchang Kim
Minchang Kim
웹/앱 개발자 김민창입니다! 좋은 하루 되세요!