[모던JS: Core] 함수 심화 (1)

KG·2021년 5월 15일
0

모던JS

목록 보기
7/47
post-thumbnail

Intro

본 포스팅은 여기에 올라온 게시글을 바탕으로 작성되었습니다.
파트와 카테고리 동일한 순서로 모든 내용을 소개하는 것이 아닌, 몰랐거나 새로운 내용 위주로 다시 정리하여 개인공부 목적으로 작성합니다.
중간중간 개인 판단 하에 필요하다고 생각될 시, 기존 내용에 추가로 보충되는 내용이 있을 수 있습니다.

Recursion

함수는 자기 자신을 다시 호출할 수 있다. 이를 재귀호출이라 하고 이때 함수는 재귀함수라고 부른다. 재귀함수는 크게 다음 조건이 필요하다.

  1. 자신의 코드블럭에서 나 자신을 호출
  2. 탈출조건

만약 2번 탈출조건이 없다면 재귀함수는 흔히 무한루프에 빠지게 된다. 보통 대부분의 재귀 함수는 단순 반복문의 형태로 변경할 수 있다. 성능적으로는 단순 반복문의 형태가 더 뛰어나지만 재귀 함수의 경우는 간결하고 가독성이 뛰어나며, 유지보수가 쉬운 코드를 만들 수 있다는 장점이 있다.

해당 게시글에서 자바스크립트에서의 재귀호출 한계에 대해 다룬적 있다. 브라우저마다 차이가 있지만, 보통 자바스크립트 엔진은 최대 재귀 깊이를 10000번 정도로 제한하고 있다. 모던 브라우저의 경우 tail calls optimazation이라는 최적화를 수행하기도 하지만 모든 경우에 적용이 불가하기에 한계가 있다.

Tail Recursion 또는 Tail Call 방식은 재귀함수의 마지막 로직에서 자신을 호출하는 방법을 말한다. 단순히 마지막 위치에 자신을 호출하는 것이 아니라, 함수 동작 가장 마지막에 호출되어야 함에 가깝다. 즉 원래 자리로 돌아가 남은 일처리를 처리할 필요 없이 해야할 작업을 모두 끝내고 나 자신을 다시 호출하여 값만 바로 반환할 수 있도록 구성하는 방식이다.

나머지 매개변수 & 전개문법

자바스크립트에서 대부분 내장 함수는 인수의 개수에 제약을 두지 않는 경우가 많다.

  • Math.max(arg1, arg2, ... argN)
  • Object.assign(dest, src1, src2, ... srcN)

이처럼 여러 개의 인수를 받아 처리하기 위해서는 함수의 인수를 나머지 매개변수로 넘겨주어야 한다.

1) 나머지 매개변수

함수에서 처리할 여분의 매개변수는 전개연산자(...)를 사용해 이름과 함께 넘겨준다. 이때 나머지 매개변수로 넘겨지는 인수는 배열의 형태로 전달된다. 이때 나머지 매개변수는 항상 마지막에 위치해야 한다.

function sumAll(...rest) {	// 이름은 고정된 형태 X
  let sum = 0;
  
  for (let el of rest) sum += el;
  
  return sum;
}

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

2) arguments 변수

함수에선 선언하지 않더라도 자체적으로 arguments라는 유사배열 객체를 가지고 있다. argumentsIterable객체이기 때문에 for...of를 통해서도 순회가 가능하다.

나머지 매개변수는 비교적 최신 문법에 해당한다 (ES6에 도입). arguments 객체를 이용해서도 함수 인수 전체를 얻어낼 수 있지만 arguments는 배열이 아닌 유사배열 객체이므로 배열관련 메서드를 바로 적용할 수 없다는 점과 나머지 매개변수처럼 인수의 일부분만을 사용할 수 없다는 단점이 있다.

function showName() {
  // arguments는 자체적으로 내장된 유사배열 객체
  // 함수로 전달된 인수에 대해 저장
  for(const name of arguments) 
    console.log(name);
}

showName('KG');		// KG
showName('KG', 'SJ');	// KG, SJ

화살표 함수의 경우엔 arguments 객체가 없다. 따라서 외부에 있는 가장 가까운 일반 함수의 arguments를 가져온다.

3) 전개문법

기존에 선언된 Iterable 객체 변수를 전개연산자(...)를 통해 함수를 호출하면, 이 객체 변수는 인수 목록으로 확장된다.

const arr = [3, 5, 1];	// 배열은 Iterable 객체

Math.max(arr);	// Error: 배열이 아닌 숫자 목록을 인수로 전달해야함
Math.max(...arr);	// 정상 동작 => 5를 반환

// 문자열도 Iterable 객체이기 때문에
// 전개연산자를 사용하면 한 글자씩 분리된 배열로 변환 가능
const str = "hello";

console.log([...str]);		// ['h', 'e', 'l', 'l', 'o']

// Array.from()과 동일한 역할
console.log(Array.from(str));	// ['h', 'e', 'l', 'l', 'o']

전개문법을 통해 얕은 복사(Shallow Copy)를 수행할 수 있다. 이는 배열뿐만이 아니라 객체도 동일하게 가능하다.

// arr과 arrCopy는 서로 같은 형식이지만
// 얕은 복사로 형식을 옮겨 다른 참조값을 가짐
const arr = [1, 2, 3];
const arrCopy = [ ...arr ];

// obj와 objCopy는 서로 같은 형식이지만
// 얕은 복사로 형식을 옮겨 다른 참조값을 가짐
const obj = { a: 1, b: 2, c: 3 };
const objCopy = { ...obj };

References

  1. https://ko.javascript.info/advanced-functions
  2. https://homoefficio.github.io/2015/07/27/%EC%9E%AC%EA%B7%80-%EB%B0%98%EB%B3%B5-Tail-Recursion/
profile
개발잘하고싶다

0개의 댓글