[Javascript] Spread / Rest
JS Spread, JS Rest, JS Spread / Rest, ...연산자, 전개 연산자
정의
같은 문법 ... 가 두 가지 의미.
- Spread : iterable 을 펼침 (right-hand)
- Rest : 나머지를 모음 (left-hand 또는 함수 매개변수)
Spread (펼침)
배열
const a = [1, 2];
const b = [...a, 3, 4]; // [1, 2, 3, 4]
const c = [0, ...a, ...a]; // [0, 1, 2, 1, 2]
const copy = [...a]; // 얕은 복사
// 함수 인자
Math.max(...[1, 2, 3]); // 3
console.log(...['a', 'b']); // a b
// string 도 iterable
[...'abc'] // ['a', 'b', 'c']
객체 (ES2018+)
const a = { x: 1, y: 2 };
const b = { ...a, z: 3 }; // { x: 1, y: 2, z: 3 }
const copy = { ...a }; // 얕은 복사
// 병합 + override
const merged = { ...defaults, ...userInput };
// userInput 이 defaults 를 덮어씀
Rest (모음)
함수 매개변수
function sum(...nums) {
return nums.reduce((a, b) => a + b, 0);
}
sum(1, 2, 3, 4); // 10
// 일부 인자 + rest
function logger(level, ...messages) {
console.log(`[${level}]`, messages.join(' '));
}
logger('INFO', 'a', 'b', 'c');
배열 destructuring
const [first, ...others] = [1, 2, 3, 4];
// first = 1, others = [2, 3, 4]
const [a, b, ...rest] = arr;
객체 destructuring
const { name, ...rest } = user;
// name = user.name, rest = 나머지 모든 속성
arguments vs rest
// 옛 스타일
function foo() {
console.log(arguments); // 유사 배열 (array-like)
Array.from(arguments).map(...); // 변환 필요
}
// 모던
function foo(...args) {
console.log(args); // 진짜 배열
args.map(...); // 바로 메서드
}
arguments 는 화살표 함수에서 안 됨, rest 는 됨.
자주 쓰는 패턴
배열 복사
const original = [1, 2, 3];
const copy = [...original]; // 얕은 복사
// 또는: Array.from(original), original.slice()
객체 복사
const copy = { ...original }; // 얕은 복사
// 깊은 복사는 structuredClone(original)
객체 병합
const config = { ...defaults, ...userOptions };
객체에서 특정 키 제외
const { password, ...safe } = user; // safe 는 password 없는 user
배열 끝/처음 추가
const newArr = [...arr, newItem]; // 끝
const newArr2 = [newItem, ...arr]; // 처음
immutable 갱신.
Math 함수 + 배열
const max = Math.max(...arr);
const min = Math.min(...arr);
함정
1. 얕은 복사
const a = [{ x: 1 }];
const b = [...a];
b[0].x = 99;
a[0].x // 99 (참조 공유)
깊은 복사는 structuredClone(obj) (ES2022+) 또는 JSON.parse(JSON.stringify(obj)) (제한적).
2. 객체 spread 의 순서
const a = { x: 1 };
const b = { x: 99, ...a }; // { x: 1 } (뒤가 우선)
const c = { ...a, x: 99 }; // { x: 99 } (뒤가 우선)
같은 키는 뒤에 오는 값이 우선.
3. iterable 만 spread
[...{ a: 1 }] // ❌ TypeError (객체는 iterable 아님)
{ ...[1, 2, 3] } // { 0: 1, 1: 2, 2: 3 } (배열을 객체로)
4. rest 의 위치
function foo(...args, last) {} // ❌ SyntaxError (rest 는 마지막)
function foo(first, ...rest) {} // ✓
5. Symbol.iterator 가 없으면
const obj = { length: 3 };
[...obj] // ❌ TypeError
Symbol.iterator 가 있는 객체만 array spread 가능.
참고
이 글의 용어 (3개)
- [Javascript] Arrayjavascript
- 정의 JavaScript 의 는 순서 있는 객체. 정수 키 + . 풍부한 메서드 (map/filter/reduce/...) 가 함수형 스타일을 지원. 생성 핵심 메서드 (반복) …
- [Javascript] Destructuringjavascript
- 정의 Destructuring 은 배열 또는 객체의 일부를 변수로 풀어내는 ES6 문법. 코드를 짧고 명시적으로. 객체 배열 함수 매개변수 자주 쓰는 idiom API 응답 분해…
- [Javascript] Objectjavascript
- 정의 JavaScript 의 는 key-value 쌍의 컬렉션. 거의 모든 non-primitive 값이 객체. 함수, 배열, 정규식도 객체. 생성 접근 수정 / 삭제 Objec…
💬 댓글