JS에는 JS 표준인 ECMAScript(이하 ES)이라는 버전이 존재한다. 가장 최신 버전은 ES2019(19년 출시)지만, ES6(SCMA Script6, 15년 출시)에서 가독성과 유지보수성을 획기적으로 향상할 수 있는 문법이 많이 추가되었다. ES6에서 추가된 기능으로 앞서 배운 let/const 키워드와 Template literals, Spread Syntax, Rest Parameter등이 있다.
Spread Syntax(전개 구문)와 Rest Parameter(나머지 변수, 국내 검색 사이트에서는 주로 rest 파라미터로 통용된다) 는 둘 다 점 세개(…)로 표현할 수 있지만, 쓰임새는 완전히 다르다.
- Spread Syntax : 이름 그대로 배열, 객체, 문자열 등을 풀어 각각의 요소로 넣어준다.
- Rest Parameter : 함수의 매개변수(parameter)를 배열[]의 형태로 받아 사용할 수 있게 한다.
1. Spread Syntax
📌 함수의 인자로 활용
function sum(x, y, z) {
return x + y + z;
}
const num3 = [1, 2, 3];
const num2 = [1, 2];
const num4 = [1, 2, 3, 4];
sum(...num3); // 6
sum(...num2); // NaN
sum(...num4); // NaN
sum(1, ...num2) // 4
sum(1, 2, ...num3) // 4
변수 number에 할당된 배열 [1, 2, 3]의 요소들이 함수 sum의 인수로 확장되었다. 요소들은 매개변수 x, y, z에 각각 들어가 함수를 실행시킨다.
하지만 예시에 보이는 것처럼, 풀어진 배열과 매개변수의 수가 일치하지 않을 경우 NaN이 출력된다. 배열의 길이가 매개변수의 길이를 초과할 경우, 들어갈 수 있는 인덱스까지만 들어간다.
📌 배열에서 활용
배열 합치기
spread 문법은 배열에서 강력한 힘을 발휘한다. 기존의 push, splice, concat등을 사용하지 않고도 훨씬 간결하게 배열을 합칠 수 있게 된 것. 또한 기존 배열을 변경하지 않는다(immutable).
let parts = ['shoulders', 'knees'];
let lyrics = ['head', ...parts, 'and', 'toes'];
lyrics // ['head', 'shoulders', 'knees', 'and', 'toes']
let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
arr1 = [...arr1, ...arr2];
// 참고: spread 문법은 기존 배열을 변경하지 않으므로(immutable), arr1의 값을 바꾸려면 새롭게 할당해야 한다.
arr1 // [0, 1, 2, 3, 4, 5]
배열 복사하기
또한 배열을 간편하게 복사할 수 있다. 배열의 요소들을 확장하여 새로운 배열에 담는 ‘얕은 복사’가 이루어진다. 복사를 해도 서로 다른 주소값을 참조하는 별개의 배열이 되는 것.
let arr = [1, 2, 3];
let newArr = [...arr]; // arr.slice()와 유사
newArr.push(4) // spread 문법은 기존 배열을 변경하지 않으므로(immutable) arr2를 수정한다고 arr이 바뀌지 않는다
arr // [1, 2, 3]
newArr // [1, 2, 3, 4]
다차원 배열 복사 유의점
하지만 다차원 배열을 복사할 때는 주의해야 한다. 복사하려는 요소가 ‘배열’일 경우, 깊은 복사가 된다. 아래 newArr[1]은 arr[1]이 가진 배열 [2, 3]의 주소값을 가진다. 때문에 같은 배열을 참조하게 된다. 따라서 newArr[1]에서 참조하는 배열의 요소를 변경하면, arr[1]도 같은 배열을 참조하고 있기 때문에 영향을 미치는 것.
let arr = [1, [2, 3], 3];
let newArr = [...arr];
newArr[1][1] = 4;
arr // [1, [2, 4], 3]
newArr // [1, [2, 4], 3]
📌 객체 리터럴
ECMAScript2018부터 객체에도 Spread Syntax를 사용할 수 있게 되었다. key-value 쌍을 확장할 수 있다. 만약 같은 key를 가지고 있으면, 기존 value를 덮어쓴다. 배열과 마찬가지로 기존 객체를 변경시키지는 않는다.
let obj1 = { foo: 'bar', x: 42 };
let obj2 = { foo: 'baz', y: 13 };
let clonedObj = { ...obj1 };
let mergedObj = { ...obj1, ...obj2 };
clonedObj // {foo: 'bar', x: 42}
mergedObj // {foo: 'baz', x: 42, y: 13} 같은 키를 가진 foo는 나중에 합쳐진 baz라는 값으로 덮어진다.
2. Rest Parameter
📌 함수에서 나머지 매개변수(parameter)받아오기
매개변수(parameter)를 배열[]의 형태로 받아서 사용 가능하다. 함수의 마지막 파라미터 앞에 …을 붙여, 함수의 인수들 중 특정 인자에 대입되지 않은 남은 인수들(rest parameter)을 하나의 배열로 묶는다. 파라미터 개수가 가변적일 때 유용하다.
function myFun(a, b, ...manyMoreArgs) {
console.log("a", a);
console.log("b", b);
console.log("manyMoreArgs", manyMoreArgs);
}
myFun("one", "two", "three", "four", "five", "six");
a one // console.log("a", a)
b two // console.log("b", b)
manyMoreArgs = ['three', 'four', 'five', 'six']
단, 마지막 배개변수만 나머지 매개변수로 설정할 수 있으며, 함수 정의에 하나의 rest parameter만 존재할 수 있다.
myFun(a, b, ...manyMoreArgs) // 가능
myFun(a, ...arg1, ...arg2) // 불가능
myFun(...manyMoreArgs, a, b) // 불가능
📌 문제로 알아보는 Rest Parameter
함수가 실행된 후, 콘솔에 출력되는 args의 값
function printMaxNums(...args) {
console.log(args)
}
printMaxNums(10, 30, 40) // [10, 30, 40]
…args는 rest parameter, rest syntax라고 부른다. 남아 있는 모든 인자를 하나의 배열에 담기 때문이다. 함수 printMaxNums의 인자는 10, 30, 40으로 총 3개이다. 이 인자를 모두 printMaxNums에 전달하여 실행한다. 실행이 되면 rest parameter arg는 모든 남아있는 인자를 할당받아, 콘솔은 배열 형태인 [10, 30, 40]을 출력하게 된다.
function printMaxNums(num1, ...args) {
console.log(args)
}
printMaxNums(10, 30, 40) // [30, 40]
만약 아래같이 따로 매개변수를 지정해 주면 어떨까? 특정 매개변수는 빠지며, 남은 매개변수만 배열의 형태로 rest parameter args에 할당된다. 즉, 콘솔은 [30, 40]을 출력한다.
다음 코드가 실행된 후, value의 값
function findBiggestArg(...args) {
let biggestArg = 0;
for (let i = 0; i < args.length; i += 1){
if (biggestArg < args[i]){
biggestArg = args[i]
}
}
return biggestArg
}
let value = findBiggestArg(10, 30, 40, 20)
for문을 확인해 보자. args의 인덱스의 값을 비교해 가장 큰 수를 돌려주는 반복문이다. 매개인자는 10, 30, 40, 20으로 들어가되, 매개변수를 …args로 받아 배열로 사용할 수 있게 만들었다. 즉, 10, 30, 40, 20을 배열 [10, 30, 40, 20]으로 받아 인덱스 값을 비교할 수 있게 된 것.
'♻️ 개발자로 재활용 > 🟢 JavaScript' 카테고리의 다른 글
일급객체(first-class citizen)와 고차함수(higher-order function) (0) | 2022.11.18 |
---|---|
DOM : 문서 객체 모델의 기본 개념 (0) | 2022.11.13 |
JavaScript Koans (1) : 연산자와 변수, 호이스팅 (0) | 2022.11.09 |
함수가 선언된 어휘적 환경, 클로저 Closure (0) | 2022.11.08 |
변수가 접근할 수 있는 범위, 스코프 Scope (0) | 2022.11.07 |