함수에 객체나 배열을 전달할때 전체가 아닌 일부만 필요한 경우가 있다. 이럴때 객체나 배열을 변수로 ‘분해’할 수 있게 해주는 문법이 구조 분해할당을 사용한다.
let triangle = {
title: "smallTriangle",
width: 100
height: 200
}
let {title, width, height} = triangle
alert(title); // smallTriangle
alert(width); // 100
alert(height); // 200
let triangle = {
title: "smallTriangle",
width: 100
height: 200
}
const {title, width: w, height: h} = triangle
// width -> w
// height -> h
// title -> title
alert(title); // smallTriangle
alert(w); // 100
alert(width) // ReferenceError: width is not defined
alert(h); // 200
let options = {
title: "triangle"
}
let {width=100, height=200, title} = options
alert(title); // Menu
alert(width); // 100
alert(height); // 200
배열 혹은 함수의 매개변수에서 했던 것처럼 객체에도 표현식이나 함수 호출을 기본값으로 할당할 수 있다.
물론 표현식이나 함수는 값이 제공되지 않았을 때 평가 혹은 실행 된다. 아래 예시를 실행하면 width 값만 물어보고 title값은 물어보지 않고 있다.
let options = {
title: "Menu"
};
let {width = "width?", title = "title?"} = options;
width //'width?'
title //'Menu' 👉 구조분해에서 할당한 값보다 객체의 프로퍼티 값이 더 우선순위인것을 알 수 있다.
콜론, 할당 연산자도 동시에 사용가능하다.
let options = {
title: "Menu"
};
let {width:w = "width?", title:t = "title?"} = options;
w // 'width?'
t // 'Menu'
나머지 패턴(rest pattern)을 사용하면 배열에서 했던것처럼 나머지 프로퍼티를 어딘가에 할당하는것이 가능하다.
(cf 모던 브라우저는 나머지 패턴 지원, 구식브라우저는 지원 안함. 물론 바벨 이용하면 가능)
let triangle = {
title: "smallTriangle",
width: 100,
height: 200
}
let {title, ...rest} = triangle
rest.width // 100
rest.height // 200
title // 'smallTriangle'
보통 let {...} = {...} 또는 const {...} = {...}이런 형식으로 구조분해를 했는데 다른 방법이 있다.
아래를 보자.
객체나 배열이 다른 객체나 배열을 포함하는 경우, 좀 더 복잡한 패턴을 사용하면 중첩 배열이나 객체의 정보를 추출할 수 있다. 이를 중첩 구조 분해(nested destructuring)이라고 한다.
let options = {
size: {
width: 100,
height: 200
},
items: ["spongeBob", "zingzingE"],
extra: true
};
let {size : {width, height}, items:[item1, item2], extra, title="animation" } = options
width // 100
height // 200
item1 // 'spongeBob'
item2 // 'zingzingE'
extra // true
title // 'animation'
🚀 주의!
위의 예시에서 size와 items 전용 변수는 없다는 점에 유의하자. 전용 변수 대신 우리는 size와 items안의 정보를 변수에 할당하였다. 아래 캡쳐본과 같이 에러 뜬다.
공부하다가.. 이것도 중첩 구조 분해의 일종인듯 하다. (아래 캡쳐본은 콘솔)
const changeTodo = (e: React.FormEvent<HTMLInputElement>) => {
console.log(e.currentTarget);
const {
currentTarget: { value },
} = e;
function triangle(title = "Untitled", width = 200, height = 100, items = []) {
// ...
}
이렇게 함수를 작성하면 넘겨주는 인수의 순서를 잘 고려해서 넘겨주어야 한다.
아래의 코드를 보자.
// 기본값을 사용해도 괜찮은 경우 아래와 같이 undefined를 여러 개 넘겨줘야 합니다.
triangle("smallTriangle", undefined, undefined, ["Item1", "Item2"])
가독성이 떨어짐을 느낄 수 있다. 꽤나 더러움.. => 이럴때 구조분해를 통해 깔끔하게 만들어보자.
// 함수에 전달할 객체
let options = {
title: "smallTriangle",
items: ["Item1", "Item2"]
};
// 똑똑한 함수는 전달받은 객체를 분해해 변수에 즉시 할당함
function triangle({title = "Untitled", width = 200, height = 100, items = []}) {
// title, items – 객체 options에서 가져옴
// width, height – 기본값
alert( `${title} ${width} ${height}` ); // smallTriangle 200 100
alert( items ); // Item1, Item2
}
triangle(options)
중첩 객체와 콜론을 섞어 좀 더 복잡한 구조 분해도 가능하다.
let options = {
title: "smallTriangle",
items: ["Item1", "Item2"]
};
// 똑똑한 함수는 전달받은 객체를 분해해 변수에 즉시 할당함
function triangle({title = "Untitled", width:w = 200, height:h = 100, items = []}) {
alert( `${title} ${w} ${h}` ); // smallTriangle 200 100
alert( item1 ); // Item1
}
triangle(options)
function({
incomingProperty: varName = defaultValue
...
})
incomingProperty는 varName에 할당된다. 만약 값이 없다면 defaultValue가 기본값으로 사용될 것이다.
참고로 이렇게 함수 매개변수를 구조 분해할 땐, 반드시 인수가 전달된다고 가정된고 사용한다는 점에 유의해야한다. 모든 인수에 기본값을 할당해 주려면 빈 객체를 명시적으로 전달해야한다.
showMenu({}); // 모든 인수에 기본값이 할당됩니다.
showMenu(); // 에러가 발생할 수 있습니다.
이 문제를 예방하려면 빈 객체 {}를 인수 전체의 기본값으로 만들면 된다.
function showMenu({ title = "Menu", width = 100, height = 200 } = {}) {
alert( `${title} ${width} ${height}` );
}
showMenu(); // Menu 100 200
이처럼 인수 객체의 기본값을 빈 객체 {}로 설정하면 어떤 경우든 분해할 것이 생겨서 함수에 인수를 하나도 전달하지 않아도 에러가 발생하지 않는다.
출처 및 참고 문헌
https://ko.javascript.info/destructuring-assignment