모던 자바스크립트 Deep Dive 정리 함수 부분

김민찬·2022년 6월 20일
0

DeepDive

목록 보기
5/6

함수

참조에 의한 전달과 외부 상태의 변경

11장에서 알아본 원시값과 객체의 비교에서 보았듯 원시값은 값에 의한 전달, 객체는 참조에 의한 전달 방식으로 동작한다. 이는 매개변수 또한 마찬가지다. 매개변수도 함수 몸체 내부에서 변수와 동일하게 취급되므로 값에 의한 전달과 참조에 의한 전달 방식을 그대로 따른다.

함수를 호출하면서 매개변수에 값을 전달하는 방식을 값에 의한 호출, 참조에 의한 호출로 구별해 부르는 경우도 있으나, 동작 방식은 값에 의한 전달, 참조에 의한 전달과 동일하다.

어떤 함수를 통해 매개변수로 전달 받은 원시타입 인수와 객체 타입 인수를 함수 몸체에서 변경할 때, 원시 타입 인수를 받은 매개변수의 경우 원시 값은 변경 불가능한 값이므로 직접 변경 할 수 없기 때문에 재할당을 통해 할당된 원시 값을 새로운 원시값으로 교체했다.

하지만 객체 타입 인수를 받은 매개변수의 경우 객체는 변경이 가능하기 때문에 재할당없이 직접 할당된 객체를 변경했다. 객체 타입 인수는 참조 값이 복사되어 매개변수에 전달되기 때문에 함수 몸체에서 참조 값을 통해 객체를 변경할 경우 원본이 훼손된다. 다시 말해 외부 상태, 즉 함수 외부에서 함수 몸체 내부로 전달한 참조 값에 의해 원본 객체가 변경되는 부수 효과가 발생한다.


(알이 후라이가 되지 않도록 하자)

이처럼 함수가 외부 상태를 변경하면 상태 변화를 추적하기 어렵다. 코드의 복잡성을 증가시키고 가독성을 해치게 된다. 복잡한 코드에서 의도치 않은 객체의 변경을 추적하는 것은 어려운 일이다. 객체의 변경을 추적하려면 옵저버 패턴 등을 통해 객체의 참조를 공유하는 모든 이들에게 변경 사실을 통지하고 이에 대처하는 추가 대응이 필요하다.

  • 옵저버 패턴?
    객체의 상태 변화를 관찰하는 관찰자 즉 옵저버들의 목록을 객체 등록하여 상태 변화가 있을 때마다 매서드 등을 통해 객체가 직접 목록의 각 옵저버에게 통지하도록 하는 디자인 패턴
  • 디자인 패턴?
    소프트웨어 공학의 디자인에서 특정 문맥에서 공통적으로 발생하는 문제에 대해 재사용 가능한 해결책이다. 'GoF의 디자인 패턴'에서는 객체지향적 디자인 패턴의 카테고리를 생성패턴, 구조패턴, 행동패턴 3가지로 구분하고 있다.

이러한 문제의 해결 방법 중 하나는 객체를 불변 객체로 만들어 사용 것이다. 객체의 복사본을 새롭게 생성하는 비용은 들지만 마치 원시값처럼 변경 불가능한 값으로 동작하게 하는 것이다.

객체의 상태 변경을 원천 봉쇄하고, 상태 변경이 필요한 경우에는 깊은 복사를 통해 새로운 객체를 생성하고 재할당을 통해 교체한다.

외부 상태를 변경하지 않고 외부 상태에 의존하지도 않는 함수를 순수 함수라고 한다. 이를 통해 부수효과를 최대한 억제하여 오류를 피하고 프로그램의 안정성을 높이려는 프로그래밍 패러다임을 함수형 프로그래밍이라 한다.

다양한 함수의 형태

즉시 실행 함수

함수 정의와 동시에 즉시 호출되는 함수를 즉시 실행 함수라고 한다. 즉시 실행 함수는 단 한번만 호출되며, 다시 호출 할 수 없다.


(실행되고 다시 호출할 수 없다.)

즉시 실행 함수는 함수 이름이 없는 익명 함수를 사용하는 것이 일반적이다. 함수이름이 있는 기명 즉시 실행 함수도 사용할 수는 있다. 그렇지만 다시 호출하는 것은 여전히 불가능하다.

즉시 실행함수는 반드시 그룹 연산자로 감싸야 한다. 그렇지 않으면 syntaxError가 발생한다.

  1. 익명 함수인 경우
  • 그룹 연산자로 감싸지 않은 경우 선언문으로 판단된다. 함수 선언문은 이름을 생략할 수 없다.
  1. 기명 함수인 경우
  • 그룹 연산자로 감싸지 않은 경우 코드 블록의 닫는 중괄호 뒤에 세미콜론이 암묵적으로 추가되기 때문에 그 위에 ()는 함수 호출이 아닌 그룹 연산자로 해석, 피연산자가 없기 때문에 에러 발생

즉 그룹 연산자로 함수를 묶은 이유는 먼저 함수 리터럴을 평가해서 함수 객체를 생성하기 위해서다.

즉시 실행 함수도 일반 함수처럼 값을 반환할 수 있고 인수를 전달할 수도 있다.

재귀함수

함수가 자기 자신을 호출하는 것을 재귀 호출이라 한다. 재귀 함수는 자기 자신을 호출하는 행위, 즉 재귀 호출을 수행하는 함수를 말한다.

함수 이름은 함수 몸체 내부에서만 유효하다. 따라서 함수 내부에서는 함수 이름을 사용해 자기 자신을 호출할 수 있다. 함수 표현식으로 정의한 함수 내부에서는 함수 이름은 물론 함수를 가리키는 식별자로도 자기 자신을 재귀 호출할 수 있다. 단 함수 외부에서 함수를 호출할 때는 반드시 함수를 가리키는 식별자로 해야한다.

재귀 함수는 자신을 무한 재귀 호출한다. 따라서 탈출 조건을 반드시 만들어야 한다.

재귀 함수는 반복되는 처리를 반복문 없이 구현할 수 있다는 장점이 있지만, 무한 반복에 빠질 위험이 있고, 이로 인해 스택 오버플로 에러를 발생시킬 수 있으므로 주의해서 사용해야 한다. 따라서 반복문보다 재귀함수가 더 직관적으로 이해하기 쉬울 때만 한정적으로 사용하는 것이 바람직하다.

중첩함수

함수 내부에 정의된 함수를 중첩함수 또는 내부함수라 한다. 그리고 내부함수를 포함한 함수는 외부함수라 부른다. 일반적으로 중첩함수는 자신을 포함하는 외부 함수를 돕는 헬퍼 함수의 역할을 한다.

중첩함수는 스코프와 클로저에 깊은 관련이 있다..


참고
모던 자바스크립트 DeepDive

중첩함수 예시

https://velog.io/@sungjun-jin/JavaScript-Functions

기타

https://ko.wikipedia.org/wiki/%EC%98%B5%EC%84%9C%EB%B2%84_%ED%8C%A8%ED%84%B4

https://readystory.tistory.com/114

https://ko.wikipedia.org/wiki/%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4_%EB%94%94%EC%9E%90%EC%

profile
프론트엔드 개발자로 나아가고 있는 김민찬입니다.

0개의 댓글