이제는 더이상 헷갈려 하고 싶지 않다...
Spread Syntax는 쉽게 말해, 배열, 객체, 문자열의 요소를 모두 꺼내준다.
function func(x, y, z) { // x=arr[0] y=arr[1] z=arr[2]
return x+y+z;
}
const arr = [1, 2, 3]
console.log(func(...arr)); // arr의 요소들이 func의 인수로 확장된다
// expected result
// 6
Spread Syntax가 도입되면서, push()
, splice()
, concat()
등을 사용하지 않고 훨씬 간결하게 배열을 합칠 수 있게 되었다.
const eng = ['hi', 'bi', 'jazz'];
const lang = ['안녕', '잘있어', '재즈', ...eng];
// ['안녕', '잘있어', '재즈', 'hi', 'bi', 'jazz']
배열과 배열을 합칠 수도 있다.
const math = ['plus', 'minus'];
const lang = ['korean', 'swedish'];
const study = [ ...math, ...lang]; // ['plus', 'minus', 'korean', 'swedish']
또한, Spread Syntax로 배열을 간편하게 복사할 수 있다. 이 때 Spread Syntax는 배열의 요소들을 확장하여 새로운 배열에 담기 때문에, 얕은 복사가 이루어진다.
아래의 예제를 보자.
const eng = ['hi', 'bi', 'jazz'];
const newEng = [...eng]; // eng 배열의 요소들이 확장되어 담긴다
newEng.push('rock');
console.log(eng); // ['hi', 'bi', 'jazz']
console.log(newEng); // ['hi', 'bi', 'jazz', 'rock']
newEng
에는 Spread Syntax를 이용해 eng
의 요소들을 복사하였다. newEng
은 eng
의 요소들을 가지고 있지만, 서로 다른 주소값을 참조하는 별개의 배열이 되었다. 따라서 newEng
에 새로운 요소를 추가해도 eng
에는 아무런 변화가 없는 것을 확인할 수 있다.
[주의!]
다차원 배열을 복사할 때는 조심해야 한다. 복사하는 요소가 배열인 경우, 그 주소를 복사한다. 다시 말해, 배열 형태의 요소는 깊은 복사를 한다. 다음의 예제를 보자.const oldNum = [1, [2, 3], 3]; const newNum = [...oldNum]; newNum[1][1] = 4; console.log(oldNum); // [1, [2, 4], 3]
newNum[1]
은oldNum[1]
이 가진[2, 3]
배열의 주소값을 가진다. 그러면oldNum[1]
과newNum[1]
은 같은 배열을 참조하게 된다. 따라서newNum[1]
이 참조하는 배열의 요소를 변경하게 되면,oldNum[1]
도 같은 배열을 참조하기 때문에 영향을 미치게 된다.
따라서 다차원 배열을 복사할 때는 배열 요소가 깊은 복사 된다는 점을 유의해야 한다!
ECMAScript2018부터 객체에도 Spread Syntax를 사용할 수 있게 되었다. 키값쌍을 확장할 수 있다.
const guest1 = { name: 'youjin', age: 25 };
const guest2 = { name: 'nittre', human: true };
const guest3 = { ...guest1 };
// { name: 'youjin', age: 25}
Spread Syntax를 이용해 다수의 객체를 복사하는 경우, 키가 겹치면 기존 키 값을 덮어쓴다.
const group = { ...guest1, ...guest2 };
// { name: 'nittre', age: 25, human: true }
비슷한 작업을 Object.assign()
메서드를 이용해 실행할 수도 있다.
Object.assign(target_obj, source_obj) 메서드
target_obj 객체에 source_obj의 속성을 복사하고, 복사된 target_obj를 리턴한다.let target = {a: 1, b: 2}; let source = {b:3, c: 5}; let returnTarget = Object.assign(target, source); console.log(returnTarget); //{a: 1, b: 3, c: 5} console.log(target); //{a: 1, b: 3, c: 5}
다만, Spread Syntax를 사용하는 경우 원본 객체가 변하지 않지만, Object.assign()
메서드를 사용하면 원본 객체가 변한다.
[주의]
객체 spread Syntax는 객체에서만 가능하다.const a_obj = {a: 1}; const arr = [...a_obj]; // Uncaught TypeError: a_obj is not iterable
Rest Parameter는 함수의 인수를 배열로 나타낼 수 있게 해준다. 함수의 마지막 파라미터의 앞에 ...
를 붙여, 함수의 인수들 중 특정 인자에 대입되지 않은 남은 인수들(rest parameters)을 하나의 배열로 묶는다.
function sumOfNums(name, ...args){
// name에는 첫번째 인수가 들어가며
// 나머지 인수들은 args 배열에 들어간다
let sum = 0;
for (let el of args){
sum += el;
}
return `${name}: ${sum}`
};
console.log(sumOfNums('from 1 to 4', 1, 2, 3, 4)); // 'from 1 to 4: 10'
구조 분해 할당을 이용해 Rest Parameter를 해체할 수도 있다.
function func(...[a, b, c]){
return a+b+c;
}
f(1); // NaN (b와 c가 undefined이기 때문)
f(1, 2, 3); // 6
f(1, 2, 3, 4); // 6 (네번째 파라미터는 해체되지 않음)
Spread Syntax와 Rest Parameter의 차이
Spread Syntax는 배열을 다른 요소로 확장하는 반면, Rest Parameter는 여러 요소를 수집하여 하나의 요소로 압축한다.
arguments 객체는 함수의 인수를 참조하는 유사 배열 객체이다.
키는 함수의 인수 순서에 따른 인덱스이다.
function func(a, b, c) {
/*
arguments는 다음과 같은 객체가 된다.
{ "0": 'hi',
"1": 'i am',
"2": 'nittre'
}
*/
console.log(arguments[0]); // 'hi'
console.log(arguments[1]); // 'i am'
console.log(arguments[2]); // 'nittre'
}
func('hi', 'i am', 'nittre');
arguments 객체는 유사 배열 객체로, Array와 비슷하지만 length
속성만을 쓸 수 있으며, push()
, pop()
등의 배열 메서드는 사용할 수 없다.
arguments 객체를 배열로 만들고 싶다면, 다음과 같은 방법을 사용할 수 있다.
// 1. Array.from() 메서드 사용
let args = Array.from(arguments);
// 2. Spread Syntax 사용
let args = [...arguments];
/* 배열 안에서 객체에 Spread Syntax를 사용할 수 없지만,
arguments 객체는 유사배열이기 때문에 가능하다 */
유사 배열 객체는
length
속성과 인덱싱된 요소를 가진 객체를 의미한다. 문자열(String)도 유사 배열 객체라고 할 수 있다.
Array.from() 메서드
Array.from()
메서드는 유사 배열 객체나 이터러블 객체를 얕게 복사하여 새로운 배열을 만든다.Array.from('foo'); // ['f', 'o', 'o']
arguments
객체는 모든 함수 인자를 대상으로 한다.arguments
객체는 유사 배열 객체인 반면, Rest Parameters로 만들어진 배열은 Array
인스턴스이다.