우리는 앞서 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.
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 로 할당했다.
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
어레이 디스트럭쳐링으로 액세스한 엘리먼트 외에 나머지 엘리먼트를 분리된 어레이에 모으고 싶을 수 있다. 결과는 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];
몇몇 경우에, 함수 인자로 들어간 오브젝트를 디스트럭쳐링 할 수 있다.
코드를 보자 :
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과 함께 유용하게 쓸 수 있는 오브젝트 리터럴 정의 방법이다.)
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);