- Math.max(arg1, arg2, ..., argN) => returns the greatest of the arguments.
- Object.assign(dest, src1, ..., srcN) => copies properties from src1..N into dest.
…and so on.
다음 예시를 보자.
function sum(a, b) {
return a + b;
}
console.log(sum(1, 2, 3, 4, 5));
위와 같은 함수가 있을 때, 주어진 인자는 1, 2, 3, 4, 5 이지만, 쓰여지는 것은 1, 2 뿐이다. 하지만 따로 에러가 나오지 않고 쓰이지 않는 숫자는 undefined로 처리해주고 쓰여지는 숫자로만 리턴값을 구성하는 것이 Javascript의 특이한 방식이다.
위의 함수를 다음과 같이 리팩토링 해보자.
function sumAll(...args) { // args is the name for the array
let sum = 0;
for (let arg of args) sum += arg;
return sum;
}
console.log(sumAll(1)); // 1
console.log(sumAll(1, 2)); // 3
console.log(sumAll(1, 2, 3)); // 6
다른 예시를 보면서 rest parameter에 대해 정확히 이해해보도록 하자.
function showName(firstName, lastName, ...titles) { // ...titles is an array.
console.log(firstName + ' ' + lastName); // Julius Caesar
// the rest go into titles array
// i.e. titles = ["Consul", "Imperator"]
console.log(titles[0]); // Consul
console.log(titles[1]); // Imperator
console.log(titles.length); // 2
}
showName("Julius", "Caesar", "Consul", "Imperator");
함수 자체의 arguments 를 콘솔에 출력해보면 rest parameter를 이해해보자.
function showName() { // arguments is a keyword of JS. and similar to array, but not. .
console.log( arguments.length );
console.log( arguments[0] );
console.log( arguments[1] );
// it's iterable
// for(let arg of arguments) alert(arg);
}
// shows: 2, Julius, Caesar
showName("Julius", "Caesar");
// shows: 1, Ilya, undefined (no second argument)
showName("Ilya");
function f() {
let showArg = () => console.log(arguments[0]); // Arrow function
showArg();
}
f(1); // 1
f(2, 3); // 2
// 참고
// "this" keyword of an arrow function denotes its surrounding context(= execution stack).
// Arrow function의 특징
// Arrow function의 this라고 하는 keyword는 자기가 아니라 자기를 둘러싸고 있는 context를 가리킨다.
다음 코드를 보면서 spread operator의 역할과 기능을 이해해보자.
let arr = [3, 5, 1];
console.log(Math.max(arr)); // null
let arr = [3, 5, 1];
console.log(Math.max(3, 5, 1)); // 5
// 맨 위의 식을 Spread operator을 이용하면 우리가 원하는 두번째 식의 결과값을 도출할 수 있다.
let arr = [3, 5, 1];
console.log(Math.max(...arr)); // 5
두 번쩨 예시도 보도록 하자.
let arr1 = [1, -2, 3, 4];
let arr2 = [8, 3, -8, 1];
console.log(Math.max(...arr1, ...arr2)); // 8
/// 위 식의 ...은 Spread이다. rest는 하나인 경우에만 쓸 수 있지 두개를 쓸 수 없다.
let merged = [0, ...arr1, 2, ...arr2];
console.log(merged) // [0, 1, -2, 3, 4, 2, 8, 3, -8, 1]
// spread는 rest와는 다르게 parameter로만 쓰이는 것이 아니다. => spread, not rest.
let merged = Math.max(0, ...arr1, 2, ...arr2);
console.log(merged) // 8
// parameter라고 하더라도 이건 rest가 아니라 spread인 이유는 일단 rest 같은 경우는 맨 뒤에서만 나올 수 있다.
// 둘째로 rest는 하나인 경우에만 쓸 수 있지 두개를 쓸 수 없디. => spread, not rest.
마지막 예시를 보도록 하자.
let str = "Hello"; // string is an array of characters.
console.log([...str]); // ["H", "e", "l", "l", "o"]
console.log(Array.from(str)); // ["H", "e", "l", "l", "o"]
// 위 두 식은 같은 결과값을 반환한다.
둘의 모양은 같지만, 하는 역할이 다르다.
그 '다름'은 문맥, 상황을 통해서만 파악할 수 있다.
Spread는 Rest와는 다르게 parameter로만 쓰이는 것이 아니다.
Rest는 하나만 쓸 수 있지 두개를 쓸 수 없고 인자로 담길 때 맨 뒤에서만 사용할 수 있다.
function adder(...a) {
console.log(a); // [1, 4, 6, 7, 3, 234]
return a.reduce((sum, number) => {
return sum + number;
}, 0)
}
const ab = adder(1, 4, 6, 7, 3, 234);
console.log(ab); // 255
---
const MathLibrary = {
multilpyTwoNumbers(a, b) {
return a * b;
},
multiply(...rest) {
return rest.reduce((total, elem) => total * elem, 1);
},
};
const a = MathLibrary.multilpyTwoNumbers(4, 5);
console.log(a); // 20
const b = MathLibrary.multiply(4, 5, 6);
console.log(a); // 120
// multilpyTwoNumbers는 multiply 메소드가 생겼기 때문에 불필요해진다.
// 하지만 이미 이를 사용하고 있던 수많은 코드가 있다면,
// 우린 다음과 같이 리팩토링을 해줄 수 있다.
multilpyTwoNumbers(a, b) {
return this.multiply(a, b);
}
// 혹은
multilpyTwoNumbers(...rest) {
return this.multiply(...rest);
}
// 위와 같이 리팩토링 해주면 이미 multilpyTwoNumbers함수를 쓰고 있는 다른 코드들은 아무런 영향을 받지 않고 정상적으로 동작할 수 있다.
const oldHeroes = ['Superman', 'Batman', 'Spiderman', 'Hulk'];
const newHeroes = ['Itonman', 'Antman', 'Storm', 'X-man'];
const totalHeroes = oldHeroes.concat(newHeores);
console.log(totalHeroes); // ['Superman', 'Batman', 'Spiderman', 'Hulk', 'Itonman', 'Antman', 'Storm', 'X-man'];
// es6 - spread operator
const newTotal = [...oldHeroes, ...newHeores];
console.log(newTotal); // ['Superman', 'Batman', 'Spiderman', 'Hulk', 'Itonman', 'Antman', 'Storm', 'X-man'];
const totalHeroesPlusAquaman = ['Aquaman', ...oldHeroes, ...newHeores];
console.log(totalHeroesPlusAquaman); // ['Aquaman', 'Superman', 'Batman', 'Spiderman', 'Hulk', 'Itonman', 'Antman', 'Storm', 'X-man'];
function validate(arg) {
if (totalHeroes.indexOf(arg) < 0){
return [arg, ...totalHeores];
}
}
const a = validate('Atom');
console.log(a); // ['Atom', 'Superman', 'Batman', 'Spiderman', 'Hulk', 'Itonman', 'Antman', 'Storm', 'X-man'];
function product(a, b, c, d, e) {
let numbers = [a, b, c, d, e];
return numbers.reduce(function (acc, number) {
return acc * number;
}, 1)
};
function unshift(array, a, b, c, d, e) {
return [a, b, c, d, e].concat(array);
};
function join(array1, array2) {
return array1.concat(array2);
};
위의 코드를 Rest parameters와 Spread operator를 사용하여 간결하게 바꾸어 보도록 하자.
function product(...rest) {
return rest.reduce((acc, number) => acc * number, 1)
};
function unshift(array, ...rest) {
return [rest, ...array];
};
function join(array1, array2) {
return [...array1, ...array2];
};