Rest parameters vs. Spread operator

이효범·2022년 4월 24일
0

ES6 - OOP & FRP

목록 보기
9/15
post-thumbnail

참고

https://javascript.info/rest-parameters-spread-operator


Rest parameters

  1. Math.max(arg1, arg2, ..., argN) => returns the greatest of the arguments.
  2. Object.assign(dest, src1, ..., srcN) => copies properties from src1..N into dest.
  • 첫 번째 argument(dest)에 두번째부터 끝까지의 argument들을 통합해서 첫 번째 argument(dest)에다가 property들을 다 copy한다. ⇒ Object.assign

 …and so on.

  • Math.max(arg1, arg2, ..., argN) 나 Object.assign(dest, src1, ..., srcN) 처럼
    중간에 ... 에 하나가 들어갈지 두개가 들어갈지 여러개가 들어갈지... 즉 몇개가 들어갈 지 모르는 경우 쓰는 게 Rest parameters 이다.
    ⇒ 즉, argument 숫자가 확정되지 않았을 때 쓸 수 있다.

다음 예시를 보자.

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 parameters를 이용한다는 것은 argument의 개수가 몇 개이든 상관없다는 것이다.
    즉, argument가 몇개가 오든 우리가 원하는 결과값을 도출 가능한 것이다.

다른 예시를 보면서 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

다음 코드를 보면서 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"]

// 위 두 식은 같은 결과값을 반환한다.

Rest parameters vs. Spread operator

둘의 모양은 같지만, 하는 역할이 다르다.
그 '다름'은 문맥, 상황을 통해서만 파악할 수 있다.
Spread는 Rest와는 다르게 parameter로만 쓰이는 것이 아니다.
Rest는 하나만 쓸 수 있지 두개를 쓸 수 없고 인자로 담길 때 맨 뒤에서만 사용할 수 있다.


Rest parameters 예제 추가

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함수를 쓰고 있는 다른 코드들은 아무런 영향을 받지 않고 정상적으로 동작할 수 있다. 

Spread operator 예제 추가

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'];

Rest parameters vs. Spread operator 연습 문제

문제

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];
};

profile
I'm on Wave, I'm on the Vibe.

0개의 댓글