ES6에 도입된 스프레드 문법 ... 은 하나로 뭉쳐있는 여러 값들의 집합을 펼처서 개별적인 값들의 목록으로 만든다.
스프레드 문법은 Array, String, Map, Set, DOM 컬렉션, arguments와 같이 for...of 문으로 순회할 수 있는 이터러블에 한정된다.
// ...[1, 2, 3]은 [1, 2, 3]을 개별 요소로 분리한다(→ 1, 2, 3)
console.log(...[1, 2, 3]); // 1 2 3
// 문자열은 이터러블이다.
console.log(...'Hello'); // H e l l o
// Map과 Set은 이터러블이다.
console.log(...new Map([['a', '1'], ['b', '2']])); // [ 'a', '1' ] [ 'b', '2' ]
console.log(...new Set([1, 2, 3])); // 1 2 3
// 이터러블이 아닌 일반 객체는 스프레드 문법의 대상이 될 수 없다.
console.log(...{ a: 1, b: 2 });
// TypeError: Found non-callable @@iterator
하지만, 이터러블이 아닌 일반 객체 또한 스프레드 문법을 이용할 수 있다.
함수 호출문의 인수 목록에서 사용하는 경우
요소들의 집한인 배열을 펼처서 개별적인 값들의 목록으로 만든 후 이를 함수의 인수 목록으로 전달할 수 있다.
const arr = [1, 2, 3];
// 배열 arr의 요소 중에서 최대값을 구하기 위해 Math.max를 사용한다.
const max = Math.max(arr); // -> NaN
Math.max 메서드는 매개변수 개수를 확정할 수 없는 가변 인자 함수이기 때문에 배열이 아닌 스프레드 메서드를 인자로 넣어줘야 한다.
const arr = [1, 2, 3];
// 스프레드 문법을 사용하여 배열 arr을 1, 2, 3으로 펼쳐서 Math.max에 전달한다.
// Math.max(...[1, 2, 3])은 Math.max(1, 2, 3)과 같다.
const max = Math.max(...arr); // -> 3
Rest 파라미터는 함수에 전달된 인수들의 목록을 배열로 전달하기 위해 매개변수 앞에 ...을 붙이지만, 스프레드 문법은 여러 개의 값이 하나로 뭉쳐있는 배열과 같은 이터러블을 펼처 개별적인 값을 목록으로 만드는 것이다. 확실하게 구분하자.
// Rest 파라미터는 인수들의 목록을 배열로 전달받는다.
function foo(...rest) {
console.log(rest); // 1, 2, 3 -> [ 1, 2, 3 ]
}
// 스프레드 문법은 배열과 같은 이터러블을 펼쳐서 개별적인 값들의 목록을 만든다.
// [1, 2, 3] -> 1, 2, 3
foo(...[1, 2, 3]);
배열 리터럴 내부에서 사용하는 경우
스프레드 문법을 이용하면 기존 방식보다 더 간결하고 가독성 좋게 표현할 수 있다.
concat 기능
// ES5
var arr = [1, 2].concat([3, 4]);
console.log(arr); // [1, 2, 3, 4]
// ES6
const arr = [...[1, 2], ...[3, 4]];
console.log(arr); // [1, 2, 3, 4]
splice 기능
// ES5
var arr1 = [1, 4];
var arr2 = [2, 3];
// 세 번째 인수 arr2를 해체하여 전달해야 한다.
// 그렇지 않으면 arr1에 arr2 배열 자체가 추가된다.
arr1.splice(1, 0, arr2);
// 기대한 결과는 [1, [2, 3], 4]가 아니라 [1, 2, 3, 4]다.
console.log(arr1); // [1, [2, 3], 4]
// ES6
const arr1 = [1, 4];
const arr2 = [2, 3];
arr1.splice(1, 0, ...arr2);
console.log(arr1); // [1, 2, 3, 4]
배열 복사
스프레드 문법을 이용해 배열의 복사를 더 간결하게 표현할 수 있다.
// ES5
var origin = [1, 2];
var copy = origin.slice();
console.log(copy); // [1, 2]
console.log(copy === origin); // false
// ES6
const origin = [1, 2];
const copy = [...origin];
console.log(copy); // [1, 2]
console.log(copy === origin); // false
이터러블을 배열로 반환
이터러블을 배열로 변환하기 위해서는 Function.prototype.apply 또는 Function.prototype.call 메서드를 사용해 slice 메서드를 호출해야 하지만 스프레드 문법을 이용하면 그럴 필요가 없다.
// ES5
function sum() {
// 이터러블이면서 유사 배열 객체인 arguments를 배열로 변환
var args = Array.prototype.slice.call(arguments);
return args.reduce(function (pre, cur) {
return pre + cur;
}, 0);
}
console.log(sum(1, 2, 3)); // 6
스프레드 문법을 이용한 코드
// 이터러블이 아닌 유사 배열 객체
const arrayLike = {
0: 1,
1: 2,
2: 3,
length: 3
};
const arr = Array.prototype.slice.call(arrayLike); // -> [1, 2, 3]
console.log(Array.isArray(arr)); // true
arguments 객체는 이터러블이면서 유사 배열 객체이기 때문에 스프레드 문법을 사용할 수 있다.
// ES6
function sum() {
// 이터러블이면서 유사 배열 객체인 arguments를 배열로 변환
return [...arguments].reduce((pre, cur) => pre + cur, 0);
}
console.log(sum(1, 2, 3)); // 6
하지만 이 경우에는 Rest 파라미터를 사용하는 것이 더 좋다.
// Rest 파라미터 args는 함수에 전달된 인수들의 목록을 배열로 전달받는다.
const sum = (...args) => args.reduce((pre, cur) => pre + cur, 0);
console.log(sum(1, 2, 3)); // 6
객체 리터럴 내부에서 사용하는 경우
스프레드 프로퍼티를 사용하면 객체 리터럴의 프로퍼티 목록에서도 스프레드 문법을 사용할 수 있다.
// 스프레드 프로퍼티
// 객체 복사(얕은 복사)
const obj = { x: 1, y: 2 };
const copy = { ...obj };
console.log(copy); // { x: 1, y: 2 }
console.log(obj === copy); // false
// 객체 병합
const merged = { x: 1, y: 2, ...{ a: 3, b: 4 } };
console.log(merged); // { x: 1, y: 2, a: 3, b: 4 }
// 객체 병합. 프로퍼티가 중복되는 경우, 뒤에 위치한 프로퍼티가 우선권을 갖는다.
const merged = { ...{ x: 1, y: 2 }, ...{ y: 10, z: 3 } };
console.log(merged); // { x: 1, y: 10, z: 3 }
// 특정 프로퍼티 변경
const changed = { ...{ x: 1, y: 2 }, y: 100 };
// changed = { ...{ x: 1, y: 2 }, ...{ y: 100 } }
console.log(changed); // { x: 1, y: 100 }
// 프로퍼티 추가
const added = { ...{ x: 1, y: 2 }, z: 0 };
// added = { ...{ x: 1, y: 2 }, ...{ z: 0 } }
console.log(added); // { x: 1, y: 2, z: 0 }
'JavaScript > 모던 자바스크립트 Deep Dive' 카테고리의 다른 글
[Deep Dive] Set과 Map (0) | 2024.08.15 |
---|---|
[Deep Dive] 디스트럭처링 할당 (0) | 2024.08.07 |
[Deep Dive] 34. 이터러블 (0) | 2024.08.01 |
[JS] 보석 쇼핑 (0) | 2024.07.31 |
[Deep Dive] 33. 7번째 데이터 타입 Symbol (0) | 2024.07.31 |