[JS] 나머지 매개변수와 스프레드 문법

학미새🐥·2023년 5월 7일
0

출처

나머지 매개 변수

  • JS에서는 함수 정의 시 선언되는 매개 변수의 개수와 무관하게 함수 호출 시 여러개의 인수를 사용할 수 있다.
    ex-
function sum(a,b) {
  return a+b;
}

console.log(sum(1,2,3,4,5,6,7)); 
// output -> 3

위의 예시처럼 sum 함수 정의 시 매개변수를 두개만 선언해주고, 호출 시 그보다 많은 인수를 전달한다면 전달한 인수에서 앞의 두개만 선택되어 반환값이 도출된다.

  • 즉, 정의된 매개변수 개수와 전달하는 인수의 개수가 달라도 오류가 발생하지 않는다!
  • 여기서 남은 인수들을 버리지 않고, 하나의 배열로 묶어둘 수 있는 방법이 바로 ...이다.
function showName(firstName, lastName, ...titles) {
  alert( firstName + ' ' + lastName ); // Bora Lee

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

showName("Bora", "Lee", "Software Engineer", "Researcher");

위의 예시에서는 매개변수로 두개의 변수를 받고, ...titles가 세번째 매개변수로 온다.
이후 호출 시 네개의 인수를 넘겨줬다.
그럼 앞에서부터 변수에 각각 할당을 해준 뒤,
남아있는 모든 인수는 ...배열 에 묶어서 담기게 된다.

  • 따라서 ... 뒤에 오는 이름은 배열명이 된다.

여기서 주의해야 할 사항은!
이러한 나머지매개변수는 각각의 매개변수에 인수를 할당한 뒤, 뒤에 남은 인수를 묶어서 저장하는 역할이기 때문에 반드시 함수 매개변수의 가장 마지막에 와야 한다.
(중간에 올 경우 에러 발생!)

arguments 객체

  • arguments는 유사배열 자료구조이다.
  • 이를 통해 함수 내에서 인덱스를 사용해서 인수에 접근할 수 있다.
  • 함수에 정의된 매개변수와 무관하게, 함수 호출 시 전달되는 모든 인수가 차례대로 arguments 배열에 담기게 된다고 이해하자.
  • 따라서 별도의 변수명을 짓지 않아도, 첫번째 인수는 arguments[0] 두번째 인수는 arguments[1] 이런식으로 접근할 수 있다.

ex-

function kopis() {
  console.log(arguments.length);
  console.log(arguments[2]+"\n");
  
  for (let arg of arguments) {
    console.log(arg);
  }
}

함수가 이렇게 정의되었을 때,

kopis("숭","빈","서","혜","민");

이렇게 호출할 경우 Output은

5
서

숭
빈
서
혜
민

만약 접근하는 인덱스에 비해 인수 개수가 부족할 땐?

kopis("숭","빈");

output은 아래와 같고, arguments에서 접근할 수 없는 인덱스는 undefined 처리가 된다.

2
undefined

숭
빈
  • arguments는 배열이 아니라 유사배열이기 때문에 배열 메소드를 사용할 수 없음에 유의하자.
  • 또 arguments는 자체 this를 지원하지 않는 Arrow Fnc에서는 지원되지 않으니 이 점도 기억하자!

스프레드 문법

위에서 다룬 내용이 여러 인수를 하나의 배열로 묶어서 처리하는 방식이었다면,
스프레드 문법은 하나의 배열을 인수로 전달해도 각 요소가 쪼개서 사용되는 방식을 얘기한다.

  • '전개 문법'이라고도 한다.
  • 나머지매개변수 처럼 ... 를 사용하지만 하는 일은 반대라는 점!
  • 나머지매개변수에서는 ...arr를 함수 정의 시 매개변수 자리에 넣어줬지만,
  • 스프레드 문법에선느 ...arr를 함수 호출인수 자리에 넣어준다.
let arr = [3, 5, 1];
alert( Math.max(...arr) ); // 5

여기서 arr는 배열이지만, max 메소드의 인수로 ...arr를 넣어주면, 실제로 max 메소드가 실행될 때는 arr 배열의 요소들의 각각의 인수로 분리되어서 인수로 담기게 된다.
즉,

  • 길이 N짜리 배열 하나 -> N개의 인수

로 확장해주는 것이 스프레드 문법의 역할이다.

이렇게 각 요소를 알알이 분리시켜주기 때문에 배열이나 새로운 값과의 결합도 용이하다.

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

alert( Math.max(...arr1, ...arr2) ); // 8
  • 위처럼 arr1, arr2를 합치는듯이 활용할 수도 있고,
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 순서로 합쳐집니다.)
  • 배열 뿐만 아닌 다른 값들과도 함께 합쳐질 수 있다.

스프레드 문법은 배열 외의 모든 iterable 객체에도 사용할 수 있다.
대표적인 문자열의 경우, 문자열에 스프레드 문법을 적용하면 배열의 요소가 각각 분리되듯이, 각각의 글자들이 분리되어 쓰인다.

배열과 객체의 복사본 만들기

배열과 객체를 복사하는 방법인 Object.assign() 외에도, 스프레드 문법을 활용하는 방식이 있다.

let arr = [1, 2, 3];
let arrCopy = [...arr]; // 배열을 펼쳐서 각 요소를 분리후, 매개변수 목록으로 만든 다음에
                        // 매개변수 목록을 새로운 배열에 할당함

// 배열 복사본의 요소가 기존 배열 요소와 진짜 같을까요?
alert(JSON.stringify(arr) === JSON.stringify(arrCopy)); // true

// 두 배열은 같을까요?
alert(arr === arrCopy); // false (참조가 다름)

// 참조가 다르므로 기존 배열을 수정해도 복사본은 영향을 받지 않습니다.
arr.push(4);
alert(arr); // 1, 2, 3, 4
alert(arrCopy); // 1, 2, 3

위의 예시에서
1. ...arr 를 통해 배열의 탈을 벗고
2. n개의 각 요소들이 분리되어 just '여러개의 값'으로 존재하다가
3. arrCopy라는 새로운 변수에 할당되며 '여러개의 값'이 다시 합쳐지게 되면

arr와 arrCopy는 참조가 다르기 때문에 복사본이 된다.

  • 객체 또한 동일하다!
let obj = { a: 1, b: 2, c: 3 };
let objCopy = { ...obj }; // 객체를 펼쳐서 각 요소를 분리후, 매개변수 목록으로 만든 다음에
                          // 매개변수 목록을 새로운 객체에 할당함

// 객체 복사본의 프로퍼티들이 기존 객체의 프로퍼티들과 진짜 같을까요?
alert(JSON.stringify(obj) === JSON.stringify(objCopy)); // true

// 두 객체는 같을까요?
alert(obj === objCopy); // false (참조가 다름)

// 참조가 다르므로 기존 객체를 수정해도 복사본은 영향을 받지 않습니다.
obj.d = 4;
alert(JSON.stringify(obj)); // {"a":1,"b":2,"c":3,"d":4}
alert(JSON.stringify(objCopy)); // {"a":1,"b":2,"c":3}
profile
뭐든 다해보려는 공대생입니다

0개의 댓글