Javascript

spread 와 rest

하루 2022. 3. 8. 21:23

ES6부터 도입된 spread와 rest 문법에 대해서 알아보자.

서로 완전히 다른 문법이지만 비슷한 부분이 있다.

 

spread

*spread: 펼치다, 퍼뜨리다

이 문법을 사용하면 객체 혹은 배열을 펼칠 수 있다.

 

const slime = {
  name: '슬라임'
};

const cuteSlime = {
  name: '슬라임',
  attribute: 'cute'
};

const purpleCuteSlime = {
  name: '슬라임',
  attribute: 'cute',
  color: 'purple'
};

console.log(slime);
console.log(cuteSlime);
console.log(purpleCuteSlime);

  • slime - 객체 선언
  • cuteSlime - 기존에 선언한 slime을 건드리지 않고 새로운 객체를 만들어서 slime 이 가지고 있는 값을 그대로 사용
  • purpleCuteSlime - cuteSlime 이 가지고 있는 속성을 그대로 사용하면서 추가적으로 color 추가

위 코드의 핵심은 기존의 것은 건드리지 않고, 새로운 객체를 만드는 것. 이러한 상황에 사용할 수 있는 유용한 문법이 spread 이다. 

 

사용법

spread 연산자는 ... 문자를 통해 사용할 수 있다. 

const slime = {
  name: '슬라임'
};

const cuteSlime = {
  ...slime,
  attribute: 'cute'
};

const purpleCuteSlime = {
  ...cuteSlime,
  color: 'purple'
};

console.log(slime);
console.log(cuteSlime);
console.log(purpleCuteSlime);

배열 적용

const animals = ['개', '고양이', '참새'];
const anotherAnimals = [...animals, '비둘기'];
console.log(animals);
console.log(anotherAnimals);

배열에서 spread 연산자를 여러번 사용할 수도 있다.

const numbers = [1, 2, 3, 4, 5];

const spreadNumbers = [...numbers, 1000, ...numbers];
console.log(spreadNumbers); // [1, 2, 3, 4, 5, 1000, 1, 2, 3, 4, 5]

 

이 때 spread 를 통해서 위의 객체를 참조하고, 같은 속성의 값을 추가로 명시해주면 기존에 있던 속성에 덮어씌워져 새로운 값이 출력된다.

const slime = {
  name: '슬라임'
};

const cuteSlime = {
  ...slime,
  attribute: 'cute'
};

const purpleCuteSlime = {
  ...cuteSlime,
  color: 'purple'
};

const greenCuteSlime = {
  ...cuteSlime,
  color: 'green'
};

console.log(slime);
console.log(cuteSlime);
console.log(purpleCuteSlime);    // {name: '슬라임', attribute: 'cute', color: 'purple'}
console.log(greenCuteSlime);     // {name: '슬라임', attribute: 'cute', color: 'green'}

 


rest

rest 는 생김새는 spread 와 비슷하지만 역할이 매우 다르다. spread 가 객체를 펼치는 것이었다면, rest 는 모아오는 것으로 생각하면 된다. rest 는 객체, 배열, 함수의 파라미터에서 사용이 가능하다.

 

객체

const purpleCuteSlime = {
  name: '슬라임',
  attribute: 'cute',
  color: 'purple'
};

const { color, ...rest } = purpleCuteSlime;
console.log(color);
console.log(rest);

rest 는 객체와 배열에서 사용할 때는 이렇게 비구조화 할당 문법과 함께 사용된다.

주로 사용할 때는 위와 같이 rest 라는 키워드를 사용하게 되는데, 추출한 값의 이름이 꼭 rest 일 필요는 없다. 

const purpleCuteSlime = {
  name: '슬라임',
  attribute: 'cute',
  color: 'purple'
};

const { color, ...cuteSlime } = purpleCuteSlime;
console.log(color);
console.log(cuteSlime);

이렇게 해도 무방하다. 

 

이어서, attribute 까지 없앤 새로운 객체를 만들고 싶다면 이렇게 하면 된다.

const purpleCuteSlime = {
  name: '슬라임',
  attribute: 'cute',
  color: 'purple'
};

const { color, ...cuteSlime } = purpleCuteSlime;
console.log(color);
console.log(cuteSlime);

const { attribute, ...slime } = cuteSlime;
console.log(attribute);
console.log(slime);

 

배열

배열에서의 rest 는 맨 마지막에 와야한다.

const numbers = [0, 1, 2, 3, 4, 5, 6];

const [one, ...rest] = numbers;

console.log(one);
console.log(rest);

배열 비구조화 할당을 통해 원하는 값을 밖으로 꺼내고, 나머지 값을 rest 안에 넣었다.

 

🚨 Error! 반면 이렇게 작성하면 에러가 뜬다.

const numbers = [0, 1, 2, 3, 4, 5, 6];

const [..rest, last] = numbers;

 

함수 파라미터

rest 를 함수 파라미터에서 사용할 수도 있다.

...rest 를 파라미터에 넣으면 함수에서 받아온 모든 파라미터를 하나의 배열로 만들어서 파라미터로 받아온다.

 

예) 파라미터로 넣어준 모든 값들을 합해주는 함수

function sum(a, b, c, d, e, f, g) {
  let sum = 0;
  if (a) sum += a;
  if (b) sum += b;
  if (c) sum += c;
  if (d) sum += d;
  if (e) sum += e;
  if (f) sum += f;
  if (g) sum += g;
  return sum;
}

const result = sum(1, 2, 3, 4, 5, 6);
console.log(result);

위에서 sum 함수는 7개의 파라미터를 받아오는데 , 아래에서 사용할 때에는 6개만 넣어주었다.

그러면 g 값이 undefined 가 되기 때문에 sum 에 더하는 과정에서 += undefined 를 하게 되어 결과는 NaN 이 된다.

그렇기 때문에 함수에서 하나하나 유효한 값인지 확인을 해줄 필요가 있다.

 

함수의 파라미터가 몇 개가 될지 모르는 상황에서 rest 파라미터를 사용하면 매우 유용하다.

function sum(...rest) {
  return rest;
}

const result = sum(1, 2, 3, 4, 5, 6);
console.log(result);

result 가 가리키고 있는 것은 함수에서 받아온 파라미터들로 이루어진 배열이다.

파라미터들이 들어가있는 배열을 받았으니, 이를 모두 더해주면 된다.

function sum(...rest) {
  return rest.reduce((acc, current) => acc + current, 0);
}

const result = sum(1, 2, 3, 4, 5, 6);
console.log(result); // 21

기본값 0 으로 시작해서 초기값 0 이 acc 이 되고, current 에 배열 [1,2,3,4,5,6] 이 차례대로 들어가져서 합산을 출력하게 된다.

 


함수 인자와 spread

먼저 파라미터와 인자의 개념에 대해서 정리해보자면

함수에서 받아오는 값파라미터라고 부른다.

그리고 함수에서 값을 넣어줄 때, 그 값들을 인자라고 부른다.

const myFunction(a) { // 여기서 a 는 파라미터
  console.log(a); // 여기서 a 는 인자
}

myFunction('hello world'); // 여기서 'hello world' 는 인자

 

방금 함수 파라미터와 rest 를 사용한 것과 비슷하지만, 반대의 역할이다. 

예를 들어서, 배열 안에 있는 원소들을 모두 파라미터로 넣어주고 싶다고 가정해보자.

function sum(...rest) {
  return rest.reduce((acc, current) => acc + current, 0);
}

const numbers = [1, 2, 3, 4, 5, 6];
const result = sum(
  numbers[0],
  numbers[1],
  numbers[2],
  numbers[3],
  numbers[4],
  numbers[5]
);
console.log(result);

이런식으로 배열의 인덱스를 일일이 작성해주어야 해서 불편하다.

이 때 sum 함수를 사용할 때 인자 부분에서 spread 를 사용한다면 다음과 같이 표현이 가능하다.

function sum(...rest) {
  return rest.reduce((acc, current) => acc + current, 0);
}

const numbers = [1, 2, 3, 4, 5, 6];
const result = sum(...numbers); // spread 적용
console.log(result);

이렇게 spread와 rest 를 잘 사용하면 앞으로 보기 깔끔한 코드를 작성하는데 도움이 된다!