[JavaScript] 나머지 매개변수로 여러 개의 인수를 변수로 전달하기 arguments, every(), call(), rest parameters

V·2021년 6월 25일
1

JavaScript 

목록 보기
2/6
post-thumbnail
  • 나머지 매개변수를 이용해 개수를 알 수 없는 다수의 매개변수를 전달하는 방법을 살펴보자.
  • 본 포스팅의 예제와 설명은 자바스크립트 코딩의 기술 도서를 참고 하였음을 밝힙니다.

지난 포스팅(해체 할당으로 키-값 할당을 축약하고 객체 생성하기)에서 객체 해체 할당으로 여러 개의 매개변수를 하나의 인수로 결합하는 방법을 살펴보았다.
그렇다면 전체 개수를 알 수 없는 매개변수들은 어떻게 처리할까?

사진 앱에서 사용자가 사진에 태그를 입력할 수 있게 하려 할 때, 태그의 길이를 일정한 글자 수 이내로 제한해야 한다고 해보자.

👶🏻 배열을 이용해 여러 항목을 매개변수에 전달하기

function validateCharacterCount(max, items) {
  return items.every(item => item.length < max);
}

위에서 사용한 Array.prototype.every() 메서드는 배열의 모든 항목을 대상으로 콜백 함수를 실행해 모든 항목에서 참 값이 반환되면 결과적으로 true를 반환하는 함수이다.

validateCharacterCount(10, ['Hobbs', 'Eagles']);
// true

함수에 문자열이 담긴 배열을 전달하여 사용할 수 있다.
이 코드는 매우 범용적인 훌륭한 코드라고 할 수 있으나 사용자에게 특정한 컬렉션 양식을 강제한다는 단점이 있다. 예를들어 이름 한건만 테스트 하는 경우에도 배열로 전달을 해야 한다.

  validateCharacterCount(10, 'wvoquine');
// TypeError: items.every is not a function
// END:typeerror

👦🏻 배열과 유사한 arguments 객체 이용해 인수를 받아보자.

사용자를 위해 매개변수를 배열로 전달해야 한다는 문장을 주석으로 작성할 수도 있겠지만 더 나은 방법이 있다. 이런 경우에는 골수 자바스크립트 개발자들의 방법으로써 함수에 내장된 arguments 객체를 이용을 고려 해 볼 수 있다.

function getArguments() {
  return arguments;
}
getArguments('Bloomsday', 'June 16');
// [ '0': 'Bloomsday', '1': 'June 16' ]

arguments 객체는 함수에 전달된 모든 인수를 가지고 있는 '배열과 유사한' 컬렉션이다. 즉, arguments가 length 속성과 더불어 0부터 인덱스된 다른 속성을 가지고 있어서 배열처럼 보이지만, 사실은 배열의 인스턴스가 아니기 때문에 Array의 forEach, map과 같은 내장 메소드를 가지고 있지 않으며 사용할 수 없다.

function validateCharacterCount(max, itemlist) {
  const items = Array.prototype.slice.call(arguments, 1); // <label id="rest.arguments" />
  return items.every(item => item.length < max);
}

👱🏻‍♂️ arguments 객체와 call() 매소드

위에서 2행의 코드는 함수의 기본 메소드인 call()을 이용해서 arguments를 조작해 배열의 내장 메소드를 사용할 수 있게 한 것이다. 배열의 slice() 매서드의 this를 바꾸어 arguments에서도 배열의 함수를 사용하게 한 것이다.(ES6에서는 Array.from()을 제공한다. )
그리고 slice()로 첫번째 인수인 글자수를 제외한 인수 목록을 받도록 했다. 이제 검사할 이름의 개수와 관계없이 인수 목록을 전달해 주면 함수의 사용이 가능해졌다.

이제 매개변수로 배열이 아닌 배열의 인수 목록을 전달해 주어야 하므로 전달할 인수가 이미 배열인 경우에는 펼침 연산자를 이용해 배열의 인수 목록을 가져와 함수를 사용할 수 있다.

validateCharacterCount(10, 'wvoquie');
// true

const tags = ['Hobbs', 'Eagles'];
validateCharacterCount(10, ...tags);
// true

이렇게 함수에 다양한 형태의 매개변수를 적용할 수 있게 되었다. 하지만 이 방법은 완벽하지 않다. 예전 방식이기도 하고, 사용자가 함수의 몸체를 살펴보기 전에는 매개변수로 인수 목록을 받는다는 사실을 알기 어렵다.

👨🏻 나머지 매개변수로 배열로 나타내기

여기에 나머지 매개변수를 사용하면 인수 목록을 전달하고, 변수에 담아 이러한 문제를 해결해 볼 수 있다.

function sum(...theArgs) {
  return theArgs.reduce((previous, current) => {
    return previous + current;
  });
}

console.log(sum(1, 2, 3));
// expected output: 6

console.log(sum(1, 2, 3, 4));
// expected output: 10

위의 코드는 인수를 배열로 나타내고 배열의 메소드를 사용하는 예시이다.
나머지 매개변수는 정해지지 않은 수의 인수를 배열로 나타낼 수 있게 해준다.

function getArguments(...args) {
  return args;
}
getArguments('Bloomsday', 'June 16');
// ['Bloomsday', 'June 16']

(...) 을 사용하여 나머지 매개변수를 작성하고, 뒤에 이를 할당할 변수 이름(arg)을 작성했다. 이후 전달되는 매개변수는 arg에 배열로 담긴다.

나머지 매개변수를 이용해서 calidateCharacterCount() 함수를 다시 작성해보자.

function validateCharacterCount(max, ...items) {
  return items.every(item => item.length < max);
}

단순하고 간결할 뿐만 아니라 예측 가능성도 높은 코드가 되었다!

validateCharacterCount(10, 'wvoquie');
// true

validateCharacterCount(10, ...['wvoquie']);
// true

const tags = ['Hobbs', 'Eagles'];
validateCharacterCount(10, ...tags);
// true

validateCharacterCount(10, 'Hobbs', 'Eagles');
// true

또한, 기존의 작성했던 함수와 동일하게 인수 목록을 전달하거나 배열을 펼침 연산자로 전달해 함수를 호출할 수 있게 되었다!

나머지 매개변수를 사용하는 몇가지 이유를 더 살펴보면 다음과 같다.

  1. 인수를 배열로 다루는 것을 다른 개발자들에게 알려야 하는 경우.

타입 검사가 없는 경우에 사용자들이 전달하는 데이터가 배열 형식일 때 개발자가 나머지 매개변수를 사용할 것이다. 함수를 호출 할 때마다 정보를 펼쳐 넣어야 하는 것이 번거롭지만, 대신 기대되는 매개변수 유형을 보여주는 명확한 표지가 된다.

  1. 코드 디버깅에 좋은 방법이 될 수 있다.

나머지 매개변수를 이용해서 추가 매개변수를 가져오는 것으로 의심되는 라이브러리 함수를 해석하는 데 도움을 얻을 수 있다. 또한, 나머지 매개변수를 사용하면 길게 나열된 인수를 확인할 수 있다.

  ['Spirited Away', 'Princess Mononoke'].map((film, ...other) => {
    console.log(other);
    return film.toLowerCase();
  });
  // [0, ['Spirited Away', 'Princess Mononoke']]
  // [1, ['Spirited Away', 'Princess Mononoke']]

map()매소드의 콜백 함수에서 검사중인 항목을 인수로 받을 때 개별 항목 외에 몇가지 인수가 더 전달된다. 매개변수의 나머지 부분을 수집해서 console.log로 표시하도록 해보면, 콜백 함수에서 검사 중인 항목의 순서와 전체 컬렉션을 전달받는 것을 확인할 수 있다.

이렇게 나머지 매개변수를 활용하면 다른 방법으로는 확인하기 어려운 매개변수를 찾는 데 도움이 될 수 있으며 이를 디버깅에 활용할 수 있을 것이다.

  1. 함수 간에 속성을 전달하면서 해당 속성을 조작할 필요가 없는 경우 사용하면 좋다.

여러 개의 함수를 감싸서 인수를 전달할 때 유용한 방법이다. 다음 예제 코드처럼 모달 창에서 변경 사항을 저장할 때 다른 함수로 정보를 갱신함과 동시에 창을 닫아야 하는 경우를 예로 들 수 있다.

function applyChanges(...args) {
  updateAccount(...args);
  closeModal();
}

👨🏻‍🦳 나머지 매개변수는 객체의 키-값 쌍이나 배열에 담긴 나머지 값을 가져올 때도 사용할 수 있다.

  const queue = ['stop', 'collaborate', 'listen'];
  const [first, ...remaining] = queue;
  first;
  // 'stop'
  remaining;
  // ['collaborate', 'listen'];

원본 배열은 그대로 유지 하면서 첫번째 값과 나머지 값이 담긴 배열을 확인할 수 있다.

인수에 나머지 매개변수를 사용하는 경우의 유일한 단점은 언제나 마지막 인수에 사용해야 한다는 것이다. 이는 해체 할당의 경우에도 마찬가지이다.

 const [...beginning, last] = queue;
 // SyntaxError: Rest element must be last element

즉, 첫 번째 항목을 반환하는 shift() 메소드는 다시 만들 수 있지만, 마지막 항목을 반환하는 pop() 메서드는 다시 만들 수 없다.

👶🏻읽어주셔서 감사합니다!!

profile
블로그 이전중 https://sungbeen.com

1개의 댓글

comment-user-thumbnail
2021년 6월 25일

잘 보고 갑니다!! 좋은 정보 감사합니다!!

답글 달기