자바스크립트 배열과 객체의 구조분해할당, 스프레드 연산자, Rest 패턴, Rest 파라미터

배열의 구조 분해 할당(Destructuring Array)

const arr = [2, 3, 4];
const [x, y, z] = arr;
console.log(x, y, z); // 2, 3, 4
  • 디스트럭쳐링(Destructuring): 복잡한 데이터 구조를 분해(비구조화)하는 것, 한국어로는 흔히 구조 분해 할당이라고 표현한다.
const restaurant = {
  name: 'Classico Italiano',
  location: 'Via Angelo Tavanti 23, Firenze, Italy',
  categories: ['Italian', 'Pizzeria', 'Vegetarian', 'Organic'],
  starterMenu: ['Focaccia', 'Bruschetta', 'Garlic Bread', 'Caprese Salad'],
  mainMenu: ['Pizza', 'Pasta', 'Risotto'],

  openingHours: {
    thu: {
      open: 12,
      close: 22,
    },
    fri: {
      open: 11,
      close: 23,
    },
    sat: {
      open: 0, // Open 24 hours
      close: 24,
    },
  },
};

const [main, , secondary] = restaurant.categories; 
  • 배열의 일부 원소만 언패킹할수도 있다.
// 아래와 같이 두 값을 서로 바꾸려면?
// const temp = main;
// main = secondary;
// secondary = temp;

[main, secondary] = [secondary, main]
  • 두 값을 서로 바꾸려면 위와 같이 할당하면 된다. (스위칭, switching)
const nested = [2, 4, [5, 6]];
// const [i, , j] = nested;
// console.log(i, j); // 2, [5, 6]
const [i, , [j, k]] = nested;
console.log(i, j, k);
  • nested array도 동시에 구조 분해 할당 할 수 있다.
// default values
// const [p, q, r] = [8, 9]
// console.log(p, q, r);
const [p = 1, q = 1, r = 1] = [8, 9]
console.log(p, q, r);
  • 패킹할 값보다 변수가 더 많으면 에러가 나지 않고, undefined가 할당 된다.
  • 위와 같은 방식으로 디폴트 값을 설정할 수 있다.

객체의 구조 분해 할당(Destructuring Object)

const { name, openingHours, categories } = restaurant;
console.log(name, openingHours, categories);
  • 쓰여진 순서와는 상관없이 객체의 프로퍼티명을 그대로 할당할 수 있다.
const { name: restaurantName, openingHours: hours, categories: tags } = restaurant;
  • 새로운 변수명으로 할당하고 싶으면 : 뒤에 변수명을 명시해주면 된다.
const { menu = [], starterMenu: starters = [] } = restaurant;
  • 해당하는 프로퍼티가 없으면 설정할 디폴트 값은 = 뒤에 명시해준다.
let a = 111;
let b = 999;
const obj = { a: 23, b: 7, c: 14 };
({ a, b } = obj);
  • 이미 선언된 변수의 값을 구조 분해 할당해서 바꾸고 싶다면 () 안에 넣어줘야한다.
    • js는 (변수 선언 없는) {} 안에는 코드 블럭이 올 것이라고 기대하기 때문에 () 없이는 에러가 난다.
// const { fri } = openingHours
// console.log(fri); // {open:11, close:23}

const { fri: { open, close } } = openingHours;
console.log(open, close); // 11, 23
  • nested object를 구조분해 할당 할때는 {} 프로퍼티명을 넣어주면 된다.
...
  orderDelivery: function ({starterIndex = 1, mainIndex = 0, time, address}) {
    // console.log(obj);
    console.log(`Order received! ${this.starterMenu[starterIndex]} 
    and ${this.mainMenu[mainIndex]} to ${address} at ${time}`)
  },
};

restaurant.orderDelivery({
  time: '22:30',
  address: 'Via del Sole, 21',
  mainIndex: 2,
  starterIndex: 2,
})
  • 함수의 인자로 객체를 넣을 경우 파라미터는 {} 안에 프로퍼티명만 넣어주면 자동으로 구조 분해 할당을 해준다.
  • 디폴트 값 등의 구조 분해 할당 기능도 당연히 사용할 수 있다.
  • 코드를 줄여주는 파워풀한 기능!

스프레드 연산자 …(Spread Operator)

const arr = [7, 8, 9];
const badNewArr = [1, 2, arr[0], arr[1], arr[2]]; // [1, 2, 7, 8, 9]

const newArr = [1, 2, ...arr]; // [1, 2, 7, 8, 9]
console.log(...newArr); // 1 2 7 8 9

const newMenu = [...restaurant.mainMenu, 'Gnocci'];
  • 스프레드 연산자 …는 이터러블(iterable)과 객체의 원소들을 개별의 값으로 편리하게 언패킹해준다.(ES6)
    • JS iterable: arrays, strings, maps, sets… NOT objects
  • 구조 분해 할당과 비슷한 역할을 하지만 스프레드 연산자는 배열 전체의 원소들을 가져오는 점에서 차이가 있다.
// Shallow Copy
const mainMenuCopy = [...restaurant.mainMenu]

// Join 2 arrays
const menu = [...restaurant.mainMenu, ...restaurant.starterMenu];
  • 복사(Shallow copy), 조인 등의 코드에 활용할 수 있다.
const str = 'Jonas';
const letters = [...str, ' ', 'S.']; // ['J', 'o', 'n', 'a', 's', ' ', 'S.']
console.log(letters);
console.log(...str); // J o n a s, 템플릿 리터럴에는 사용 불가
  • 문자열에 스프레드 연산자를 사용할 경우
const newRestaurant = { foundedIn: 1998, ...restaurant, founder: 'Guiseppe' }
console.log(newRestaurant); // {foundedIn: 1998, name: 'Classico Italiano', location: 'Via Angelo Tavanti 23, Firenze, Italy', categories: Array(4), starterMenu: Array(4), …}
  • 객체에 스프레드 연산자를 사용할 경우

Rest 패턴(Rest Pattern)

// SPREAD, because of RIGHT side of =
const arr = [1, 2, ...[3, 4]];

// REST, because of LEFT side of =
const [a, b, ...others] = [1, 2, 3, 4, 5]
console.log(a, b, others); // 1 2 [3, 4, 5]

const [pizza, , risotto, ...otherFood] = [...restaurant.mainMenu, ...restaurant.starterMenu]
console.log(pizza, risotto, otherFood); // Pizza Risotto ["Focaccia", "Bruschetta", ...]
  • 스프레드 연산자와 같이 …를 사용하지만 Rest 패턴은 원소들을 배열로 패킹하는 역할을 한다.
    • 스프레드 연산자의 반대 역할
  • 둘을 구분하기 위해서는 =의 왼쪽에 있는지, 오른쪽에 있는지를 확인하면 된다.
    • 왼쪽: REST, 오른쪽: SPREAD
const { sat, ...weekdays } = restaurant.openingHours;
console.log(weekdays); // {thu: {...}, fri: {...}}
  • 객체에도 Rest 패턴을 활용할 수 있다.

Rest 파라미터(Rest Parameter)

const add = function (...numbers) {
  console.log(numbers);
}

add(2, 3); // [2, 3]
add(2, 3, 4, 5); // [2, 3, 4, 5]


const x = [23, 5, 7];
add(...x);
  • Rest 파라미터를 사용할 경우 인자들이 패킹되어 함수 안에서 배열로 사용할 수 있다.
...
  orderPizza: function (mainIngredient, ...otherIngredients) {
    console.log(mainIngredient);
    console.log(otherIngredients);
  },
};

restaurant.orderPizza('mushrooms', 'onions', 'olives', 'spinach');
restaurant.orderPizza('mushrooms'); // mushrooms []