본문 바로가기
JS

구조 분해(Destructuring), 나머지/전개 연산자(Rest/Spread Operator)

by Hyeon_E 2024. 6. 12.

구조 분해(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 

구조 분해 할당

자바스크립트 {...} [...] 문법 (비구조화 할당/구조분해 할당)

[JavaScript] 전개 연산자 ( Spread Operator )

매개변수 기본값, Rest 파라미터, Spread 문법, Rest/Spread 프로퍼티

'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

댓글