surf core js : 나머지 매개변수와 전개 문법

Dino_·2021년 9월 4일
0

surf javascript

목록 보기
23/28
post-thumbnail

🌳 나머지 매개변수 ...

자바스크립트는 함수 정의 방법과 상관없이 함수에 넘겨주는 인수의 개수엔 제약이 없다.

function sum(a, b) {
  return a + b;
}

alert( sum(1, 2, 3, 4, 5) );

함수를 정의할 땐 인수를 두 개만 받도록 하고, 실제 함수를 호출할 땐 이보다 더 많은 ‘여분의’ 인수를 전달했지만, 에러가 발생하지 않는다.

다만 반환 값은 처음 두 개의 인수만을 사용해 계산된다.

이렇게 여분의 매개변수는 그 값들을 담을 배열 이름을 마침표 세 개 ...뒤에 붙여주면 함수 선언부에 포함시킬 수 있다.

이때 마침표 세 개 ...는 "나머지 매개변수들을 한데 모아 배열(iterable)에 집어넣어라."는 것을 의미한다.

아래 예시에선 모든 인수가 배열 args에 모인다.

function sumAll(...args) { // args는 배열의 이름입니다.
  let sum = 0;

  for (let arg of args) sum += arg;

  return sum;
}

alert( sumAll(1) ); // 1
alert( sumAll(1, 2) ); // 3
alert( sumAll(1, 2, 3) ); // 6

앞부분의 매개변수는 변수로, 그 이외의 매개변수들은 배열로 모을 수도 있다.

function showName(firstName, lastName, ...titles) {
  alert( firstName + ' ' + lastName ); // Julius Caesar

  // 나머지 인수들은 배열 titles의 요소가 됩니다.
  // titles = ["Consul", "Imperator"]
  alert( titles[0] ); // Consul
  alert( titles[1] ); // Imperator
  alert( titles.length ); // 2
}

showName("Julius", "Caesar", "Consul", "Imperator");

나머지 매개변수는 항상 마지막에 있어야 한다.

🍃 ‘arguments’ 변수

arguemnts라는 특별한 유사 배열 객체(array-like object)를 이용하면 인덱스를 사용해 모든 인수에 접근할 수 있다.

function showName() {
  alert( arguments.length );
  alert( arguments[0] );
  alert( arguments[1] );

  // arguments는 이터러블 객체이기 때문에
  // for(let arg of arguments) alert(arg); 를 사용해 인수를 나열할 수 있습니다.
}

// 2, Julius, Caesar가 출력됨
showName("Julius", "Caesar");

// 1, Bora, undefined가 출력됨(두 번째 인수는 없음)
showName("Bora");

나머지 매개변수는 비교적 최신의 문법이다. 과거엔 함수의 인수 전체를 얻어내는 방법이 arguments를 사용하는 것밖에 없었다고 한다.

arguments는 유사 배열 객체이면서 이터러블(반복 가능한) 객체이다. 결국 배열은 아니기 때문에 배열 메서드를 사용할 수 없다는 단점이 있다.

arguments.map (...)을 호출할 수 없다.

여기에 더하여 arguments는 인수 전체를 담기 때문에 나머지 매개변수처럼 인수의 일부만 사용할 수 없다는 단점도 있다.

따라서 배열 메서드를 사용하고 싶거나 인수 일부만 사용하고자 할 때는 나머지 매개변수를 사용하는 것이 좋다.

화살표 함수에는 'arguments'가 없습니다.

화살표 함수에서 arguments 객체에 접근하면, 외부에 있는 ‘일반’ 함수의 arguments 객체를 가져온다.

function f() {
  let showArg = () => alert(arguments[0]);
  showArg();
}

f(1); // 1

🌳 spread 문법

개발을 하다 보면 매개변수를 배열로 받아오는 기능의 반대 기능이 필요할 때가 생긴다. 배열을 통째로 매개변수에 넘겨주는 것 같이 말이다.

내장 함수 Math.max는 인수로 받은 숫자 중 가장 큰 숫자를 반환하는데, 예시를 살펴보자.

alert( Math.max(3, 5, 1) ); // 5

let arr = [3, 5, 1];

alert( Math.max(arr) ); // NaN

아무런 조작 없이 배열을 ‘있는 그대로’ Math.max에 넘기면 원하는 대로 동작하지 않는다. Math.max는 배열이 아닌 숫자 목록을 인수로 받기 때문이다.

스크립트가 돌아갈 때 실제 넘어오는 배열의 길이는 아주 길 수도 있고, 아예 빈 배열일 수도 있는데, 수동으로 이걸 다 처리하다 보면 코드가 지저분해질 것이다.

전개 문법(spread syntax) 은 이럴 때 사용하기 위해 만들어졌다.

...를 사용하기 때문에 나머지 매개변수와 비슷해 보이지만, 전개 문법은 나머지 매개변수와 반대의 역할을 한다.

함수를 호출할 때 ...arr를 사용하면, 이터러블 객체 arr이 인수 목록으로 '확장’됩니다.

Math.max를 사용한 예시로 다시 돌아가보면

let arr = [3, 5, 1];

alert( Math.max(...arr) ); // 5 (전개 문법이 배열을 인수 목록으로 바꿔주었습니다.)

아래와 같이 이터러블 객체 여러 개를 전달하는 것도 가능하다.

let arr1 = [1, -2, 3, 4];
let arr2 = [8, 3, -8, 1];

alert( Math.max(...arr1, ...arr2) ); // 8

//전개 문법을 평범한 값과 혼합해 사용하는 것도 가능하다.

let arr1 = [1, -2, 3, 4];
let arr2 = [8, 3, -8, 1];

alert( Math.max(1, ...arr1, 2, ...arr2, 25) ); // 25

//배열을 합칠 때 전개 문법을 활용할 수도 있다.

let arr = [3, 5, 1];
let arr2 = [8, 9, 15];

let merged = [0, ...arr, 2, ...arr2];

alert(merged); // 0,3,5,1,2,8,9,15 (0, arr, 2, arr2 순서로 합쳐집니다.)

앞선 예시들에선 배열을 대상으로 전개 문법이 어떻게 동작하는지 살펴보았지만, 배열이 아니더라도 이터러블 객체면 전개 문법을 사용할 수 있다.

let str = "Hello";

alert( [...str] ); // H,e,l,l,o

전개 문법은 for..of와 같은 방식으로 내부에서 iterator(반복자)를 사용해 요소를 수집한다.

메서드 Array.from은 문자열 같은 이터러블 객체를 배열로 바꿔주기 때문에 Array.from을 사용해도 동일한 작업을 할 수 있다.

let str = "Hello";

// Array.from은 이터러블을 배열로 바꿔줍니다.
alert( Array.from(str) ); // H,e,l,l,o

Array.from(obj)와 [...obj]에는 다음과 같은 미묘한 차이가 있다.

Array.from은 유사 배열 객체와 이터러블 객체 둘 다에 사용할 수 있습니다.

전개 문법은 이터러블 객체에만 사용할 수 있습니다.

이런 이유때문에 무언가를 배열로 바꿀 때는 전개 문법보다 Array.from이 보편적으로 사용된다.

🍃 iterable과 like-array object

  • 이터러블(iterable) : 메서드 Symbol.iterator가 구현된 객체
  • 유사 배열(array-like) : 인덱스와 length 프로퍼티가 있어서 배열처럼 보이는 객체

브라우저나 등의 호스트 환경에서 자바스크립트를 사용해 문제를 해결할 때 이터러블 객체나 유사 배열 객체 혹은 둘 다인 객체를 만날 수 있다.

이터러블 객체(for..of 를 사용할 수 있음)이면서 유사배열 객체(숫자 인덱스와 length 프로퍼티가 있음)인 문자열이 대표적인 예이다.

이터러블 객체라고 해서 유사 배열 객체는 아니며 유사 배열 객체라고 해서 이터러블 객체인 것도 아니다.

아래 예시의 객체는 유사 배열 객체이긴 하지만 이터러블 객체가 아니다.

let arrayLike = { // 인덱스와 length프로퍼티가 있음 => 유사 배열
  0: "Hello",
  1: "World",
  length: 2
};

// Symbol.iterator가 없으므로 에러 발생
for (let item of arrayLike) {}

이터러블과 유사 배열은 대개 배열이 아니기 때문에 push, pop 등의 메서드를 지원하지 않는다.

🌳 Reference

profile
호기심 많은 청년

0개의 댓글