구조 분해(Destructuring)
구조 분해 할당은 배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 JavaScript 표현식
즉, 배열([]) 혹은 객체({}) 안의 값을 편하게 꺼내 쓸 수 있는 문법
▶ 배열 구조 분해
좌항이 호출될 변수의 집합, 우항이 할당할 값
좌항의 각 요소에는 각 index를 가지는 배열값이 할당됨
let a = [1, 2, 3, 4, 5];
let [b, c] = x;
console.log(b); // 1
console.log(c); // 2
필요하지 않은 배열 요소를 쉼표(,)을 이용해 무시할 수 있음
let [a, ,b] = [1, 2, 3];
console.log(a); // 1
console.log(b); // 3
변수에 기본값을 할당하면, 분해한 값이 undefined일 때 그 값을 대신 사용함
let [a = 5, b = 7] = [1];
console.log(a); // 1
console.log(b); // 7
하나의 구조 분해 표현식으로 두 변수의 값을 교환할 수 있음
let a = 1;
let b = 3;
[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1
배열의 길이보다 더 많은 변수에 값을 할당하는 경우 할당 이후 남은 변수에는 undefined 할당
let [a, b, c] = [1, 2];
console.log(a); // 1
console.log(b); // 2
console.log(c); // undefined
전개 연산자(...)를 사용해 좌항에서 명시적으로 할당되지 않은 나머지 배열 값들을 사용할 수 있음
let [a, b, ...rest] = [1, 2, 3, 4, 5]
console.log(a) // 1
console.log(b) // 2
console.log(rest) // [3, 4, 5]
전개 연산자 이후에 변수를 입력하면 에러 발생
let [a, b, ...rest, c] = [1, 2, 3, 4, 5] // SyntaxError: Rest element must be last element
▶ 객체 구조 분해
let a = { b: 42, c: true };
let { b, c } = a;
console.log(b); // 42
console.log(c); // true
구조 분해를 통해 변수의 선언과 분리하여 변수에 값을 할당할 수 있음
이때 꼭 괄호('()')로 감싸주어야 함(객체 리터럴이 아니라 블록으로 간주하기 때문에 괄호로 객체임을 명시)
let a, b;
({ a, b } = { a: 1, b: 2 });
나머지 연산자(...)를 사용해 좌항에서 명시적으로 할당되지 않은 나머지 객체 값들을 사용할 수 있음
let { a, b, ...rest } = { a: 10, b: 20, c: 30, d: 40 };
a; // 10
b; // 20
rest; // { c: 30, d: 40 }
객체로부터 속성을 해체하여 객체의 원래 속성명과 다른 이름의 변수에 할당할 수 있음
let a = { b: 42, c: true };
let { b:bb, c:cc } = a;
console.log(bb); // 42
console.log(cc); // true
객체로부터 해체된 값이 undefined인 경우, 변수에 기본값을 할당할 수 있으며 새로운 할당과 기본값 할당을 한번에 할 수 있음
let { a = 10, b:bb = 5 } = { a: 3 };
console.log(a); // 3
console.log(bb); // 5
계산된 속성 이름(computed property name)은, 객체 리터럴과 비슷하게 구조 분해에도 사용될 수 있음
let key = "z";
let { [key]: foo } = { z: "bar" };
console.log(foo); // "bar"
활용
함수 매개변수의 기본값 설정
function drawES2015Chart({
size = "big",
cords = { x: 0, y: 0 },
radius = 25,
} = {}) {
console.log(size, cords, radius);
// 차트 그리기 수행
}
drawES2015Chart({
cords: { x: 18, y: 30 },
radius: 30,
});
함수의 원형에서 구조 분해된 좌변에 빈 오브젝트 리터럴을 할당({size = 'big', cords = {x: 0, y: 0}, radius = 25} = {})
위의 예시와 같이 어떤 매개변수 없이도 호출할 수 있지만 우변의 빈 오브젝트 할당을 없앤다면 함수 호출시 적어도 하나의 인자가 제공되어야 함
함수가 어떠한 매개변수 없이도 호출할 수 있길 원한다면 지금 형태(빈객체 할당)가 유용하고, 무조건 객체를 넘기길 원하는 경우에는 빈 객체를 할당 하지 않는 것이 유용함
중첩된 객체 및 배열의 구조 분해
const metadata = {
title: "Scratchpad",
translations: [
{
locale: "de",
localization_tags: [],
last_edit: "2014-04-14T08:43:37",
url: "/de/docs/Tools/Scratchpad",
title: "JavaScript-Umgebung",
},
],
url: "/ko/docs/Tools/Scratchpad",
};
const {
title: englishTitle,
translations: [{ title: localeTitle }],
} = metadata;
console.log(englishTitle); // "Scratchpad"
console.log(localeTitle); // "JavaScript-Umgebung"
for of 반복문과 구조 분해
const people = [
{
name: "Mike Smith",
family: {
mother: "Jane Smith",
father: "Harry Smith",
sister: "Samantha Smith",
},
age: 35,
},
{
name: "Tom Jones",
family: {
mother: "Norah Jones",
father: "Richard Jones",
brother: "Howard Jones",
},
age: 25,
},
];
for (var {
name: n,
family: { father: f },
} of people) {
console.log("Name: " + n + ", Father: " + f);
}
// "Name: Mike Smith, Father: Harry Smith"
// "Name: Tom Jones, Father: Richard Jones"
함수 매개변수로 전달된 객체에서 필드 해제하기
function userId({ id }) {
return id;
}
function whois({ displayName: displayName, fullName: { firstName: name } }) {
console.log(displayName + " is " + name);
}
const user = {
id: 42,
displayName: "jdoe",
fullName: {
firstName: "John",
lastName: "Doe",
},
};
console.log("userId: " + userId(user)); // "userId: 42"
whois(user); // "jdoe is John"
나머지/전개 연산자(Rest/Spread Operator)
▶ 나머지 연산자(Rest Operator)
나머지 연산자는 세 개의 점('...')으로 표현
함수 매개변수 목록이나 배열, 객체의 마지막에 위치해 나머지 모든 인수를 배열로 수집함
나머지 매개변수(Rest Parameter)
매개변수 이름 앞에 '...'을 붙여서 정의한 매개변수를 의미
나머지 매개변수는 함수에 전달된 인수들의 목록을 배열로 전달받음
function f(...rest) {
console.log(Array.isArray(rest)); // true
console.log(rest); // [ 1, 2, 3, 4, 5 ]
}
f(1, 2, 3, 4, 5);
함수에 전달된 인수들은 순차적으로 파라미터와 나머지 매개변수에 할당됨
function f(param, ...rest) {
console.log(param); // 1
console.log(rest); // [ 2, 3, 4, 5 ]
}
foo(1, 2, 3, 4, 5);
function f2(param1, param2, ...rest) {
console.log(param1); // 1
console.log(param2); // 2
console.log(rest); // [ 3, 4, 5 ]
}
f2(1, 2, 3, 4, 5);
나머지 매개변수는 먼저 선언된 매개변수에 할당된 인수를 제외한 나머지 인수들이 모두 배열에 담겨 할당됨
따라서 나머지 매개변수는 반드시 마지막 파라미터이어야 함
function foo( ...rest, param1, param2) { }
foo(1, 2, 3, 4, 5);
// SyntaxError: Rest parameter must be last formal parameter
Rest 파라미터는 함수 정의 시 선언한 매개변수 개수를 나타내는 함수 객체의 length 프로퍼티에 영향을 주지 않음
function foo(...rest) {}
console.log(foo.length); // 0
function bar(x, ...rest) {}
console.log(bar.length); // 1
function baz(x, y, ...rest) {}
console.log(baz.length); // 2
나머지 매개변수를 사용하여 가변 인자의 목록을 배열로 전달 받을 수 있음
function sum(...args) {
console.log(Array.isArray(args)); // true
return args.reduce((pre, cur) => pre + cur);
}
console.log(sum(1, 2, 3, 4, 5)); // 15
▶ 전개 연산자(Spread Operator)
배열이나 객체를 확장하거나 분해하는 데 사용됨
세 개의 점('...')으로 표현되며, 배열, 객체 또는 함수 호출에서 사용
const arr = [1,2,3];
let test_arr = [4,5,6];
let test_arr2 = [4,5,6];
test_arr.push(arr);
console.log(test_arr); // [4, 5, 6, [1, 2, 3]]
test_arr2.push(...arr);
console.log(test_arr2); // [4, 5, 6, 1, 2, 3]
push를 이용할 때 전개 연산자를 사용하지 않은 코드는 array 전체가 들어가 2차원 배열이 되었지만,
전개 연산자를 사용하게 되면 array 내부의 요소 하나하나가 삽입
const obj = {
"Name":"AJu",
"Git":"zoz0312"
}
const test_obj = {
"test1":1,
"test2":2
}
const a_merge = { obj, test_obj }
const b_merge = { ...obj, ...test_obj }
console.log(a_merge);
/*
{
obj: {
"Name":"AJu",
"Git":"zoz0312"
},
test_obj: {
"test1":1,
"test2":2
}
}
*/
console.log(b_merge);
/*
{
"Name":"AJu",
"Git":"zoz0312",
"test1":1,
"test2":2
}
*/
배열 복사
spread 연산자를 사용하면 concat 메서드를 대체할 수 있으며, 훨씬 간단하게 배열 복사가 가능함
보다 간결하고 가독성 좋게 표현할 수 있음
// ES5
var arr = [1, 2, 3];
console.log(arr.concat([4, 5, 6])); // [ 1, 2, 3, 4, 5, 6 ]
// ES6
const arr = [1, 2, 3];
// ...arr은 [1, 2, 3]을 개별 요소로 분리
console.log([...arr, 4, 5, 6]); // [ 1, 2, 3, 4, 5, 6 ]
spread 연산자를 사용하여 좀 더 간편하게 할 수 있음
const veggie = ["tomato", "cucumber", "beans"];
// 배열 복사및 수정: spread 연산자로 똑같은 배열을 만들고 그 배열에 값 추가
const newVeggie = [...veggie, "peas"];
// 새로운 값이 추가된 배열
console.log(newVeggie); // ["tomato", "cucumber", "beans", "peas"]
// 원본 배열의 변경은 없음
console.log(veggie); // ["tomato", "cucumber", "beans"]
spread 문법은 복사할때 1 레벨에 깊이에서는 효과적으로 동작하지만 다차원 배열을 복사하는 것은 적합하지 않음
복사한 객체는 1depth의 값에서만 깊은 복사를 실행하기 때문
Reference
자바스크립트 {...} [...] 문법 (비구조화 할당/구조분해 할당)
'JS' 카테고리의 다른 글
Class(extends, super) (0) | 2024.06.12 |
---|---|
맵(Map), 셋(Set) (0) | 2024.06.12 |
ES-Module(ESM, ECMAScript Modules) (0) | 2024.06.11 |
화살표 함수(Arrow Function) (1) | 2024.06.11 |
템플릿 리터럴(template literal) (1) | 2024.06.11 |
댓글