상당수의 자바스크립트 내장 함수는 임의의 수의 인수를 허용합니다.
예시:
Math.max(arg1, arg2, ..., argN) – 인수 중 가장 큰 수를 반환합니다.
Object.assign(dest, src1, ..., srcN) – src1..N의 프로퍼티를 dest로 복사합니다.
기타 등등
이번 챕터에서는 이렇게 임의의 수의 인수를 받는 방법에 대해 알아보겠습니다. 또한 함수의 매개변수에 배열을 전달하는 방법에 대해서도 알아보겠습니다.
기존의 것을 건들이지 않고, 새로운 객체를 만들 때 유용함.
이 문법을 사용하면, 객체 혹은 배열을 펼칠수있습니다.
지금까지 매개변수 리스트를 배열로 가져오는 방법에 대해 살펴보았습니다.
그런데 개발을 하다 보면 반대되는 기능이 필요할 때가 생깁니다. 배열을 통째로 매개변수에 넘겨주는 것 같이 말이죠.
예시를 통해 이런 경우를 살펴봅시다. 내장 함수 Math.max는 인수로 받은 숫자 중 가장 큰 숫자를 반환합니다.
alert( Math.max(3, 5, 1) ); // 5
배열 [3, 5, 1]이 있는데, 이 배열에 Math.max를 호출할 수 있을까요?
아무런 조작 없이 배열을 “있는 그대로” Math.max에 넘기면 원하는 대로 동작하지 않습니다. Math.max는 배열이 아닌 숫자형 인수를 받기 때문입니다.
let arr = [3, 5, 1];
alert( Math.max(arr) ); // NaN
Math.max (arr [0], arr [1], arr [2]) 처럼 숫자를 수동으로 나열할 수도 있는데 배열 길이를 알 수 없기 때문에 이마저도 불가능합니다. 스크립트가 돌아갈 때 배열 내 요소가 아주 많을 수도, 아예 없을 수도 있죠. 수동으로 이걸 다 처리하다 보면 코드가 지저분해집니다.
전개 연산자(spread operator)는 이럴 때 사용하기 위해 만들어졌습니다. 전개 연산자는 ...를 사용하기 때문에 나머지 매개변수와 비슷해 보이지만, 나머지 매개변수와 반대의 역할을 해주죠.
함수를 호출할 때 ... arr를 사용하면, 반복 가능한 객체 arr이 인수 리스트로 "확장"됩니다.
Math.max를 사용한 예시로 다시 돌아가 봅시다.
let arr = [3, 5, 1];
alert( Math.max(...arr) ); // 5 (전개 연산자가 배열을 인수 리스트 바꿔주었습니다.)
아래와 같이 이터러블 여러 개를 전달하는 것도 가능합니다.
let arr1 = [1, -2, 3, 4];
let arr2 = [8, 3, -8, 1];
alert( Math.max(...arr1, ...arr2) ); // 8
전개 연산자를 평범한 값과 혼합해 사용하는 것도 가능하죠.
let arr1 = [1, -2, 3, 4];
let arr2 = [8, 3, -8, 1];
alert( Math.max(1, ...arr1, 2, ...arr2, 25) ); // 25
전개 연산자를 활용해 배열을 병합할 수도 있습니다.
let arr = [3, 5, 1];
let arr2 = [8, 9, 15];
let merged = [0, ...arr, 2, ...arr2];
alert(merged); // 0,3,5,1,2,8,9,15 (0, arr, 2, arr2 순서로 합쳐집니다.)
위 예시에선 배열을 대상으로 어떻게 전개 연산자가 동작하는지 보여줬는데 배열이 아니더라도 이터러블이라면 전개 연산자를 사용할 수 있습니다.
const slime = {
name: '슬라임'
};
const cuteSlime = {
name: '슬라임',
attribute: 'cute'
};
const purpleCuteSlime = {
name: '슬라임',
attribute: 'cute',
color: 'purple'
};
위 코드의 핵심은 기존의 객체는 수정하지 않고 새로운 객체를 만드는 것인데요.
이 때 spread 문법을 사용하면 다음과 같이 작성 할 수 있습니다.
const slime = {
name: '슬라임'
};
const cuteSlime = {
...slime,
attribute: 'cute'
};
const purpleCuteSlime = {
...cuteSlime,
color: 'purple'
};
함수의 정의 방법과 상관없이 함수를 호출할 때 넘겨주는 인수의 개수엔 제약이 없습니다.
아래와 같이 말이죠.
function sum(a, b) {
return a + b;
}
alert( sum(1, 2, 3, 4, 5) );
함수를 정의할 땐 인수를 두 개만 받을 수 있다고 정의했고, 실제 함수를 호출할 땐 이보다 더 많은 인수를 전달하였는데 에러가 발생하지 않습니다. 하지만 반환 값은 당연히 처음 두 개의 인수만을 이용해 계산되죠.
마침표 세 개 ... 뒤에 배열 이름을 적어준 후 함수 선언부의 매개변수 자리에 넣어주면 나머지 매개변수를 배열에 넣어줄 수 있습니다. 마침표 세 개 ...가 의미하는 바는 "나머지 매개변수들을 한데 모아 배열에 집어넣어라"라는 의미를 갖죠.
아래 예시에선 모든 인수가 배열 args에 모입니다.
function sumAll(...args) { // args는 배열의 이름입니다.
let sum = 0;
for (let arg of args) sum += arg;
return sum;
}
alert( sumAll(1) ); // 1
alert( sumAll(1, 2) ); // 3
alert( sumAll(1, 2, 3) ); // 6
앞부분의 매개변수는 변수로, 남아있는 매개변수들은 배열로 모을 수도 있습니다.
아래 예시에선 처음 두 인수는 변수에, 나머지 인수는 titles이라는 배열에 할당됩니다.
function showName(firstName, lastName, ...titles) {
alert( firstName + ' ' + lastName ); // Julius Caesar
// 나머지 인수들은 배열 titles에 할당됩니다.
// titles = ["Consul", "Imperator"]
alert( titles[0] ); // Consul
alert( titles[1] ); // Imperator
alert( titles.length ); // 2
}
showName("Julius", "Caesar", "Consul", "Imperator");
나머지 매개변수는 항상 마지막에 있어야 합니다.
나머지 매개변수는 “남아있는” 인수 모두를 모으는 역할을 하므로 아래 예시에선 에러가 발생합니다.
function f(arg1, ...rest, arg2) { // ...rest 후에 arg2가 있으면 안 됩니다.
// 에러
}
...rest는 항상 마지막에 있어야 합니다.
객체에서의 예시를 알아볼까요?
const purpleCuteSlime = {
name: '슬라임',
attribute: 'cute',
color: 'purple'
};
const { color, ...rest } = purpleCuteSlime;
console.log(color); // purple
console.log(rest); // Object {attribute: 'cute', color: 'purple'}
rest 안에 name 값을 제외한 값이 들어있습니다.
rest 는 객체와 배열에서 사용 할 때는 이렇게 비구조화 할당 문법과 함께 사용됩니다. 주로 사용 할때는 위와 같이 rest 라는 키워드를 사용하게 되는데요, 추출한 값의 이름이 꼭 rest 일 필요는 없습니다.
"..."는 전개 연산자나 나머지 매개변수로 사용됩니다.
안녕하세요 혹시 const { color, …rest } = purpleCuteSlime; 이부분에서
rest 에 color 를 제외한 나머지가 들어가야 할거 같은데
내용에 name 을 제외한으로 되어있어서 한번 확인 부탁드립니다.