ES6에서는 '...'와 같이 다소 특이한 형태의 문법이 추가되었습니다.
점 3개가 연달아 붙어있는 이 표시는 Spread Operator(스프레드 오퍼레이터, 스프레드 연산자, 전개 구문, 펼침 연산자...)를 나타내는 것으로, 배열, 함수, 객체 등을 다루는 데 있어서 매우 편리하고 재미(?) 있는 새로운 기능을 제공한다.
이번 글에서는 스프레드 연산자에 대해서 살펴보도록 하겠다.
❗ Spread Operator 기본 문법
스프레드 연산자를 사용하면 배열, 문자열, 객체 등 반복 가능한 객체 (Iterable Object)를 개별 요소로 분리할 수 있습니다.
간단한 예를 들면 다음과 같은 표현을 들 수 있다.
// Array
let arr1 = [1, 2, 3, 4, 5];
let arr2 = [...arr1, 6, 7, 8, 9];
console.log(arr2); // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
// String
let str1 = 'paper block';
let str2 = [...str1];
console.log(str2); // [ "p", "a", "p", "e", "r", " ", "b", "l", "o", "c", "k" ]
ES6에 추가된 새로운 내용 중스프레드 연산자는 연결, 복사 등의 용도로 꽤 활용도가 높은 편이다.
이번 글에서는 스프레드 연산자가 자주 사용될 법한 예제 위주로 설명하도록 하겠다
❗ 배열에서의 Spread Operator
✔배열 병합 (Array Concatenation)
기존에 두 개의 배열을 결합하는 데 있어서 concat 메서드를 이용하곤 했다.
ES6에서는 spread 연산자를 이용하여 좀 더 깔끔한 배열 병합이 가능하다.
// 기존 방식
let arr1 = [1,2,3];
let arr2 = [4,5,6];
let arr = arr1.concat(arr2);
console.log(arr); // [ 1, 2, 3, 4, 5, 6 ]
// ES6 spread operator
let arr1 = [1,2,3];
let arr2 = [4,5,6];
let arr = [...arr1, ...arr2];
console.log(arr); // [ 1, 2, 3, 4, 5, 6 ]
또한 Spread 연산자를 이용하면 다양한 형태의 배열 병합을 비교적 간단하게 수행할 수 있다.
let arr1 = [1,2,3];
let arr2 = [4,5,6];
arr1.push(...arr2)
console.log(arr1); // [1,2,3,4,5,6]
let arr1 = [1,2];
let arr2 = [0, ...arr1, 3, 4];
console.log(arr2); // [0, 1, 2, 3, 4]
✔ 배열 복사 (Copying Arrays)
JavaScript에서 배열을 새로운 변수에 할당하는 경우 새로운 배열은 기존 배열을 참조한다.
따라서 새로운 배열을 변경하는 경우 원본 배열 역시 변경된다.
// 단순 변수 할당
let arr1 = ['철수','영희'];
let arr2 = arr1;
arr2.push('바둑이');
console.log(arr2); // [ "철수", "영희", "바둑이" ]
// 원본 배열도 변경됩니다.
console.log(arr1); // [ "철수", "영희", "바둑이" ]
배열 참조가 아닌 배열 복사를 위해서 기존에는 slice 또는 ES5의 map을 이용하여 배열을 복사했다.
// Javascript array 복사
let arr1 = ['철수','영희'];
let arr2 = arr1.slice();
arr2.push('바둑이');
console.log(arr2); // [ "철수", "영희", "바둑이" ]
// 원본 배열은 변경되지 않습니다.
console.log(arr1); // [ "철수", "영희" ]
// ES5 map
let arr1 = ['철수','영희'];
let arr2 = arr1.map((item) => item);
arr2.push('바둑이');
console.log(arr2); // [ "철수", "영희", "바둑이" ]
// 원본 배열은 변경되지 않습니다.
console.log(arr1); // [ "철수", "영희" ]
ES6의 Spread 연산자를 사용하면, 다음과 같이 새로운 복사된 배열을 생성할 수 있습니다.
// ES6 spread operator
let arr1 = ['철수','영희'];
let arr2 = [...arr1];
arr2.push('바둑이');
console.log(arr2); // [ "철수", "영희", "바둑이" ]
// 원본 배열은 변경되지 않습니다.
console.log(arr1); // [ "철수", "영희" ]
참고로 Spread 연산자를 이용한 복사는 얕은(shallow) 복사를 수행하며, 배열 안에 객체가 있는 경우에는 객체 자체는 복사되지 않고 원본 값을 참조한다. 따라서 원본 배열 내의 객체를 변경하는 경우 새로운 배열 내의 객체 값도 변경된다.
let arr1 = [{name: '철수', age: 10}];
let arr2 = [...arr1];
arr2[0].name = '영희';
console.log(arr1); // [ {name:'영희', age: 10}]
console.log(arr2); // [ {name:'영희', age: 10}]
❗ 함수에서의 Spread Operator
✔ Rest Parameter
함수를 호출할 때 함수의 매개변수(parameter)를 spread operator로 작성한 형태를 Rest parameter라고 부른다.
Rest Parameter를 사용하면 함수의 파라미터로 오는 값들을 모아서 "배열"에 집어넣는다.
이를 통해서 깔끔한 함수 표현을 적용할 수 있습니다.
바로 예제를 살펴보자.
function add(...rest) {
let sum = 0;
for (let item of rest) {
sum += item;
}
return sum;
}
console.log( add(1) ); // 1
console.log( add(1, 2) ); // 3
console.log( add(1, 2, 3) ); // 6
위의 결과에서 보이듯이, Rest parameter를 이용하면 인자의 개수에 상관없이 모든 인자를 더하는 함수를 쉽게 구현할 수 있다. (기존 JavaScript에서는 "arguments"를 이용하여 처리할 수 있다.)
다음과 같이 기본 인자를 섞어서 사용하는 방법도 가능하다.
function addMul(method, ...rest){
if (method === 'add') {
let sum = 0;
for (let item of rest) {
sum += item;
}
return sum;
} else if (method === 'multiply'){
let mul = 1;
for (let item of rest) {
mul *= item;
}
return mul;
}
}
console.log( addMul('add', 1,2,3,4) ); // 10
console.log( addMul('multiply', 1,2,3,4) ); // 24
단, Rest파라미터는 항상 제일 마지막 파라미터로 있어야 한다.
function addMul (...rest, method){ }와 같은 방식으로는 사용할 수 없다.
✔ 함수 호출 인자로 사용
위의 경우와 반대로, 함수 정의 쪽이 아니라 함수를 Call 할 때 spread operator를 사용할 수 있다.
기존에는 배열로 되어있는 내용을 함수의 인자로 넣어주려면 풀어서 넣어주던지,
Apply를 이용했어야 하지만 spread operator를 이용하면 배열 형태에서 바로 함수 인자로 넣어줄 수 있습니다.
가장 간단한 예로 Math 함수를 예로 들어보겠다.
let numbers = [9, 4, 7, 1];
Math.min(...numbers); // 1
Map 하고 섞으면 다음과 같이도 응용이 가능하다 !
let input = [{name:'철수',age:12}, {name:'영희',age:12}, {name:'바둑이',age:2}];
//가장 어린 나이 구하기.
let minAge = Math.min( ...input.map((item) => item.age) );
console.log(minAge); // 2
❗ 객체에서의 Spread Operator
ES2018 (ES9)에서는 객체와 관련된 사항이 추가되었다.
배열에 대한 Spread Opeator를 지원하는 최근의 브라우저는 객체에 대한 Spread Operator 역시 지원한다.
✔ 객체 복사 또는 업데이트
객체에서 spread operator를 이용하여 객체의 복사 또는 프로퍼티를 업데이트 할 수 있다.
간단한 State Management 구현을 위해서 다음과 같은 방식으로 응용하여 사용하기도 한다.
let currentState = { name: '철수', species: 'human'};
currentState = { ...currentState, age: 10};
console.log(currentState)// {name: "철수", species: "human", age: 10}
currentState = { ...currentState, name: '영희', age: 11};
console.log(currentState); // {name: "영희", species: "human", age: 11}
위에서 두번째 예제는 객체의 프로퍼티를 오버라이드 함으로써 객체가 업데이트되는 것을 이용한 내용이다.
❗ Destructuring
Spread Operator는 배열이나 객체에서의 destructuring에 사용될 수 있다.
이 경우에 의미적으로는 spread operator라기보다는 rest parameter에 가까운 형태가 된다.
let a, b, rest;
[a, b] = [10, 20];
console.log(a); // 10
console.log(b); // 20
[a, b, ...rest] = [10, 20, 30, 40, 50]; // a => [0], b => [1] 이외에는 ...rest
console.log(rest); // [30,40,50]
({a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40});
console.log(a); // 10
console.log(b); // 20
console.log(rest); // {c: 30, d: 40}
'자바스크립트 - Vanilla JS' 카테고리의 다른 글
[자바스크립트 / Vanilla JS] forEach()와 map()의 차이점 (3) | 2023.01.09 |
---|---|
[자바스크립트 / Vanilla JS] parseInt()와 Number()의 차이점 (0) | 2022.09.22 |
[자바스크립트 / Vanilla JS] 클래스 (class) 총정리 (2) | 2022.09.19 |
[자바스크립트 / Vanilla JS] Array(배열) - filter, reduce, map (1) | 2022.09.14 |
[자바스크립트 / Vanilla JS] 디스트럭처링이란 ? (객체 디스트럭처링, 배열 디스트럭처링) (1) | 2022.09.13 |