자바스크립트 딥다이브 - 스프레드 문법

ChoiYongHyeun·2023년 12월 22일
1

스프레드 문법

스프레드 문법은 말 그대로 이터러블한 자료구조들을 펼치는 문법이다.

... 을 이용해서 펼칠 수 있다.

console.log(...[1, 2, 3]); // 1 2 3
console.log(...'HELLO'); // H E L L O
console.log(...{ a: 1 }); // TypeError: Spread syntax requires ...iterable[Symbol.iterator] to be a function

객체는 [Symbol.iterator] 가 없기 때문에 불가능한 모습을 볼 수 있다.

이 때 스프레드 문법은 이티러블한 객체를 나열하는 것일 뿐, 새로운 값을 생성하는 연산자가 아니다.

const arr = [1,2,3]

const spread = ...arr // SyntaxError: Unexpected token '...'

마치 Rest 문법과 비슷한 것처럼 느껴지지만 정 반대의 내용이다.

Rest 문법과 Spread 문법

Rest 문법은 나열되어 있는 인수들을 하나의 배열로 만들어주는 문법이였다.

몇 개의 인수가 들어올지 모르는 함수에서

function sum() {
  const arr = Array.from(arguments);
  return arr.reduce((pre, cur) => pre + cur, 0);
}

console.log(sum(1, 2, 3, 4, 5)); // 15

이렇게 arugment 프로퍼티를 가지고 접근하는 방식에서

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

console.log(sum(1, 2, 3, 4, 5)); // 15

몇 개의 인수가 들어올지 모르는 경우에서 나열된 인수들을 배열 형태로 나열하는게 Rest문법이였다면

Spread 문법은 오히려 자료구조를 해체하여 나열하는 것이다.

예를 들어

console.log(Math.max(1, 2, 3, 4, 5)); // 5

Math.max 같은 경우엔 나열되어있는 인수들 중 최대 값을 설정하는 것인데

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

console.log(Math.max(arr)); // NaN

배열 자체는 하나의 객체이기 때문에 최대값을 구하는게 불가능하다.

이를 해결하기 위해

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

console.log(Math.max(...arr)); // 5

값들이 담긴 자료구조를 오히려 나열해주는 것이 Spread 문법이다.

배열 리터럴 내부에서 사용하는 경우

concat

이전 챕터인 배열 파트에서 spread 문법을 사용했었다.

두 가지 배열을 합쳐 하나의 배열을 만들고 싶을 때는 concat 문법을 사용했었다.

const arr1 = [1, 2];
const arr2 = [3, 4];

const result = arr1.concat(arr2);
console.log(result); // [1,2,3,4]

하지만 이는 Array.prototype.concat 메소드를 호출하는 것이기 때문에 오버헤드가 존재한다.

이를 spread 문법을 통해 더 빠르고 효율적으로 할 수 있다.

const arr1 = [1, 2];
const arr2 = [3, 4];

const result = [...arr1, ...arr2];
console.log(result); // [ 1, 2, 3, 4 ]

splice

splice 는 특정 인덱스부터 값을 삭제하거나, 추가하는 것이 가능했다.

const arr1 = [1, 2];
const arr2 = [3, 4];

arr1.splice(1, 0, arr2);
console.log(arr1); // [ 1, [ 3, 4 ], 2 ]

1번째 인덱스부터 arr2 에 담긴 값들을 넣고 싶어서 사용하면 이처럼 객체 자체가 들어간다.

하지만 Spread 문법을 사용하면 ?

const arr1 = [1, 2];
const arr2 = [3, 4];

arr1.splice(1, 0, ...arr2);
console.log(arr1); // [ 1, 3, 4, 2 ]

값들이 나열되어 들어가기 때문에 잘 들어간다

배열 복사

배열을 복사 할 때는 slice 를 이용한다고 했다.

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

const newarr = arr.slice();
console.log(newarr); // [1, 2, 3, 4, 5]
console.log(arr === newarr); // false

slice 는 얕은 복사이다.

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

const newarr = [...arr]; // [1, 2, 3, 4, 5]
console.log(arr === newarr); // false

이 또한 spread문법을 이용해서 쉽게 할 수 있다.

객체 리터럴 복사

const obj = { a: 1, b: 2 };
const newobj = { ...obj };

console.log(newobj); // { a: 1, b: 2 }
console.log(newobj === obj); // false

스프레드 문법을 이용해 얕은 복사를 시행 할 수 있다.

얕은 복사이기 때문에 중첩 되어 있는 객체는 동일하게 참조한다.

const obj = {
  gender: 'female',
  information: {
    name: 'lee',
    age: 16,
  },
};

const newobj = { ...obj };
console.log(newobj === obj); // false
console.log(newobj.information === obj.information); // true

엥 ? 객체는 이터러블 객체가 아니라 스프레드 문법 안되는거 아닌가요?
스프레드를 이용해 프로퍼티를 지정하는 스프레드 프로퍼티 제안은 일반 객체 대상으로도 허용된다.

profile
빨리 가는 유일한 방법은 제대로 가는 것이다

1개의 댓글

comment-user-thumbnail
2023년 12월 22일

스프레드 문법이 익숙해지면 유용하게 사용할 수 있을 것 같네요 좋은 글 감사합니다.

답글 달기