기존 배열에 기반한 새로운 배열을 만들 때, 우리는 loop 과정이 필요합니다.
const arr = [7, 8, 9];
const badNewArr = [1, 2, arr[0], arr[1], arr[2]];
console.log(badNewArr);
기존 배열에 1, 2 원소를 집어넣고 싶을 때 위와 같은 방법이 있으나 굉장히 귀찮은 일입니다.
이것을 해결하기 위해 spread 연산자가 있습니다.
Spread 문법(Spread Syntax, ...)는 대상을 개별 요소로 분리한다. Spread 문법의 대상은 iterable 이어야 합니다
iterable이란 Symbol.iterator 메소드를 구현하거나 프로토타입 체인에 의해 상속한 객체를 말합니다.
즉, for...of 문으로 순회할 수 있는 객체를 말합니다.
spread 연산자의 사용법은 아래와 같습니다.
const arr = [7, 8, 9];
const newArr = [1, 2, ...arr]; // [1, 2, 7, 8, 9];
console.log(newArr); // [1, 2, 7, 8, 9];
console.log(...newArr); // 1, 2, 7, 8, 9
...[기존 배열] 형태를 통해 spread 연산자를 이용하는데 이는 기본적으로 배열을 모든 개별 요소로 확장하는 역할을 하게 됩니다. spread 연산자는 arr에서 모든 값을 가져오고 수동으로 모든 것을 개별적으로 작성합니다.
만약 두번째 출력문과 같이 spread 연산자를 출력하게 되면 리스트 형태가 아닌 개별요소 형태로 출력을 하게 됩니다.
배열의 개별적인 요소가 필요하게 되면 spread 연산자를 사용하면 됩니다.
// ...[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
// 이터러블이 아닌 일반 객체는 Spread 문법의 대상이 될 수 없다.
console.log(...{ a: 1, b: 2 });
// TypeError: Found non-callable @@iterator
spread 연산자는 array를 작성하거나 다수의 요소를 pass할 때 유용합니다.
const restaurant = {
mainMenu: ['Pizza', 'Pasta', 'Risotto']
};
const newMenu = [...restaurant.mainMenu, 'Spagetti'];
console.log(newMenu);
위와 같이, 객체 안의 key 안에 들어있는 배열들을 새롭게 정의할 수도 있습니다.
spread 연산자는 destructing과 비슷한 부분이 가장 결정적인 차이는 spread 연산자는 새로운 변수들을 만들지 않습니다.
spread 연산자는 다양하게 쓰일 수 있습니다.
1) 배열의 복사 또는 Join 하기
const restaurant = {
starterMenu: ['Bread', 'Salad', 'Focaccia'],
mainMenu: ['Pizza', 'Pasta', 'Risotto']
};
const newMenu = [...restaurant.mainMenu, 'Spagetti'];
console.log(newMenu);
// 배열 복사하기
const mainMenuCopy = [...restaurant.mainMenu];
// Join 2 arrays
const menu = [...restaurant.starterMenu, ...restaurant.mainMenu]
console.log(menu)
배열을 복사할 수 있을 뿐만 아니라 Join을 통해 새로운 배열을 합쳐서 만들 수도 있습니다.
2) 개별적 인자로 새로운 배열 만들기
const str = 'kchmin';
const letters = [...str, ' ', 'S. ']; // ["k", "c", "h", "m", "i", "n", " ", "S. "]
console.log(letters);
위와 같이 spread 연산자를 통해 문자열을 배열의 각각의 요소로 배열안에 만들수도 있습니다.
3) 함수의 인수로서 사용하기
배열을 분해하여 배열의 각 요소를 파라미터에 전달하고 싶은 경우, Function.prototype.apply를 사용하는 것이 일반적이다.
// ES5
function foo(x, y, z) {
console.log(x); // 1
console.log(y); // 2
console.log(z); // 3
}
// 배열을 분해하여 배열의 각 요소를 파라미터에 전달하려고 한다.
const arr = [1, 2, 3];
// apply 함수의 2번째 인수(배열)는 분해되어 함수 foo의 파라이터에 전달된다.
foo.apply(null, arr);
// foo.call(null, 1, 2, 3);
ES6의 Spread 문법(…)을 사용한 배열을 인수로 함수에 전달하면 배열의 요소를 분해하여 순차적으로 파라미터에 할당한다.
// ES6
function foo(x, y, z) {
console.log(x); // 1
console.log(y); // 2
console.log(z); // 3
}
// 배열을 foo 함수의 인자로 전달하려고 한다.
const arr = [1, 2, 3];
/* ...[1, 2, 3]는 [1, 2, 3]을 개별 요소로 분리한다(→ 1, 2, 3)
spread 문법에 의해 분리된 배열의 요소는 개별적인 인자로서 각각의 매개변수에 전달된다. */
foo(...arr);
앞에서 살펴본 Rest 파라미터는 Spread 문법을 사용하여 파라미터를 정의한 것을 의미한다. 형태가 동일하여 혼동할 수 있으므로 주의가 필요하다.
/* Spread 문법을 사용한 매개변수 정의 (= Rest 파라미터)
...rest는 분리된 요소들을 함수 내부에 배열로 전달한다. */
function foo(param, ...rest) {
console.log(param); // 1
console.log(rest); // [ 2, 3 ]
}
foo(1, 2, 3);
/* Spread 문법을 사용한 인수
배열 인수는 분리되어 순차적으로 매개변수에 할당 */
function bar(x, y, z) {
console.log(x); // 1
console.log(y); // 2
console.log(z); // 3
}
// ...[1, 2, 3]는 [1, 2, 3]을 개별 요소로 분리한다(-> 1, 2, 3)
// spread 문법에 의해 분리된 배열의 요소는 개별적인 인자로서 각각의 매개변수에 전달된다.
bar(...[1, 2, 3]);
Rest 파라미터는 반드시 마지막 파라미터이어야 하지만 Spread 문법을 사용한 인수는 자유롭게 사용할 수 있다.
// ES6
function foo(v, w, x, y, z) {
console.log(v); // 1
console.log(w); // 2
console.log(x); // 3
console.log(y); // 4
console.log(z); // 5
}
// ...[2, 3]는 [2, 3]을 개별 요소로 분리한다(→ 2, 3)
// spread 문법에 의해 분리된 배열의 요소는 개별적인 인자로서 각각의 매개변수에 전달된다.
foo(1, ...[2, 3], 4, ...[5]);
2. Rest Property
Rest Property는 spread 연산자랑 생긴게 비슷합니다. spread 연산자는 새로운 배열을 만들 때 사용되거나 여러 값을 함수에 전달하기 위해 사용합니다. rest 가 요소를 배열로 압축할 때, spread 연산자는 배열의 압축을 풉니다.
... 형태인 spread 연산자는 = 연산자 오른쪽에 나오지만, ... 형태를 = 연산자 왼쪽에서도 사용할 수 있습니다.
= 연산자 왼쪽에 ... 형태를 사용한 것을 Rest 라고 합니다.
1) Destructing 에서 사용되는 Rest
Rest 라고 불리는 이유는 요소의 나머지 부분이기 때문입니다. Rest는 배열의 나머지 요소를 새 배열에 넣습니다. Rest 패턴은 기본적으로 비구조화 할당에서 사용되지 않는 요소를 수집합니다.
// = 연산자 오른쪽에 있는 spread 연산자
const arr = [1, 2, ...[3, 4]];
// = 연산자 왼쪽에 있는 rest 연산자
const [a, b, ...others] = [1, 2, 3, 4, 5];
console.log(a, b, others); // 1, 2 [3, 4, 5]
위의 예시의 2번째를 보면 = 옆에 있는 Rest 패턴을 볼 수 있습니다. 1, 2는 각각 a,b에 비구조화 할당되었지만 나머지는 사용이 되지 않았습니다. 이 때 Rest를 이용하면 1, 2, [3, 4, 5]가 나옵니다. 배열 형태로 나온 이유는 사용되지 않은 배열의 나머지 요소를 새로운 배열에 넣기 때문입니다.
const restaurant = {
starterMenu: ['Focaccia', 'Bruschetta', 'Galic Bread', 'Focaccia'],
mainMenu: ['Pizza', 'Pasta', 'Risotto']
};
const [pizza, , risotto, ...otherFood] = [
...restaurant.mainMenu,
...restaurant.starterMenu,
];
console.log(pizza, risotto, otherFood);
위의 예시는 Rest 와 Spread 연산자를 같이 사용한 예시입니다.
여기서는 배열의 요소로 pizza, ,Risotto 와 Rest = restaurant 객체의 starterMenu, mainMenu 프로퍼티를 조인하고 있습니다. Rest 구문은 나머지 구문은 마지막 변수 이후의 모든 배열을 수집합니다.
Rest는 항상 비구조화 할당의 나머지여야합니다. 그래야만 JavaScript가 나머지 배열을 언제까지 수집할지 알기 때문입니다. 그렇게 된다면 Pizza Risotto ["Focaccia", "Bruschetta", "Galic Bread", "Focaccia"] 를 출력하게 됩니다.
2) Function 에서 사용되는 Rest
const add = function (...numbers) {
let sum = 0;
for(let i = 0; i < numbers.length; i++){
sum += numbers[i];
}
console.log(sum);
}
add(2, 3);
add(1, 2, 3, 4, 5, 6, 7, 8);
매개변수가 많을 때에는 Rest 패턴의 Rest parameter를 통해 해결할 수 있습니다. Rest는 여러 숫자 또는 여러 값을 취한 다음 모두 하나의 배열로 압축합니다.
참고
'Language > JavaScript' 카테고리의 다른 글
[JavaScript] 매개변수 (0) | 2021.01.14 |
---|---|
[JavaScript] default parameter 설정하는 방법 (0) | 2021.01.13 |
[JavaScript] Destructuring (0) | 2021.01.12 |
[JavaScript] 함수 호출 방식에 달라지는 this (0) | 2021.01.12 |
[JavaScript] 호이스팅(Hoisting) (0) | 2021.01.12 |
댓글