[JS Deep Dive] 12장. 함수

lyshine·2023년 3월 31일
0

JS Deep Dive 정리

목록 보기
9/18

함수는 자바스크립트에서 가장 중요한 핵심 개념

  • 스코프, 실행컨텍스트, 클로저, 생성자 함수에 의한 객체 생성, 메서드, this, 프로토타입 모듈화 등 모두 함수와 연관
  • 함수는 일련의 과정을 문으로 구현하고 코드블록으로 감싸서 하나의 실행 단위로 정의한 것이다.
  • 함수의 구성요소 : 매개변수, 인수, 반환값
  • 함수 정의를 통해 생성하고 함수를 호출한다. 함수를 호출하면 반환값 리턴
//함수 정의
function add(x,y) {
	return x+y;
}
//함수 호출
var result = add(2,5);
console.log(result);//7(반환값)

함수를 사용하는 이유

  • 함수사용시 코드의 재사용이 매우 유용하다.
  • 유지보수의 편의성 증가, 코드의 신뢰성 증가
  • 적절한 함수이름을 붙여 역할을 파악을 쉽게 해준다. → 코드의 가독성 향상

함수 리터럴

  • 자바스크립트의 함수는 객체 타입의 값이다. 함수도 함수 리터럴로 생성할 수 있다.
//변수에 함수 리터럴을 할당
var f = function add(x,y) {
	return x+y;
};
  • 함수 리터럴의 구성요소
    • 함수이름 : 함수 이름은 식별자로 식별자 네이밍 규칙 준수해야 한다. 함수 이름은 함수 몸체 내에서만 참조할 수 있는 식별자다. → 함수 몸체 외부에서는 함수 이름으로 함수를 호출할 수 없다.
    • 매개변수 목록 : 각 매개변수에는 함수를 호출할때 짖ㅇ한 인수가 순서대로 할당된다.
    • 함수 몸체 : 함수 호출시 실행될 문들을 하나의 실행 단위로 정의한 코드블록

함수 정의

  • 함수 정의란 함수를 호출하기 이전에 인수를 전달받을 매개변수와 실행할 문들, 반환할 값을 지정하는 것이다.
  • 정의된 함수는 자바스크립트 엔진에 의해 평가되어 함수 객체가 된다.
    • 함수 정의 방식
      • 함수 선언문 function add(x,y){ return x+y; }
      • 함수 표현식 var add = function (x,y) {return x+y; }
      • Function 생성자 함수 var add = new Function('x','y','return x+y');
      • 화살표 함수(es6) var add = (x,y) => x+y;

함수 선언문

  • 함수 이름 생략할 수 없다.
  • 표현식이 아닌 문이여서 변수에 할당이 불가하다. 하지만 함수 선언문이 변수에 할당되는 것처럼 보일때가 있다. → 이는 함수 선언문이 아닌 함수 리터럴 표현식으로 해석된 것이다. (두개는 형태가 동일하기 때문)
    • 기명함수 리터럴을 단독으로 사용하면 함수 선언문으로 해석
    • 기명함수 리터럴을 피연산자로 사용하면 함수 리터럴 표현식으로 해석 (함수이름 생략 가능)
  • 자바스크립트 엔진은 함수 선언문으로 생성된 함수를 호출하기 위해 “함수 이름과 동일한 이름의 식별자를 암묵적으로 생성”하고 거기에 함수 객체를 할당한다.
  • 함수는 함수 이름으로 호출하는 듯하지만 함수 객체를 가리키는 식별자로 호출한다.

함수 표현식

  • 자바스크립트 함수는 일급 객체다.→ 함수를 값처럼 자유롭게 사용 가능
  • 함수리터럴로 생성한 함수 객체를 변수에 할당하는 방식을 함수 표현식이라 한다.
  • 함수리터럴의 함수 이름 생략 가능(익명 함수)
  • 함수 선언문은 “표현식이 아닌 문”
    함수 표현식은 “표현식인 문”으로 중요한 차이가 있다.

함수 생성 시점과 함수 호이스팅

//함수 참조
console.dir(add); //f add(x,y)
console.dir(sub); //undefined
//함수 호출
console.log(add(2,5)); //7
console.log(sub(2,5)); //TypeError: sub is not a function
//함수 선언문
function add(x,y) {
	return x+y;
}
//함수 표현식
var sub = function (x,y) {
	return x-y;
};
  • 함수 선언문으로 정의한 함수는 함수 선언문 이전에 호출할 수 있지만 함수 표현식으로 정의한 함수는 함수 표현식 이전에 호출할 수 없다.
  • 함수 선언문과 표현식으로 정의한 함수의 생성시점은 다르다.
    • 선언문 : 런타임 이전에 먼저 함수 객체가 생성되고 식별자에 할당된다. ⇒ 선언문은 이전에 함수 호출 가능. "함수 호이스팅"
    • 표현식 : 런타임에 평가되어 할당문이 실행되는 시점에 평가되어 함수 객체가 된다. 함수 호이스팅이 아닌 변수 호이스팅이 발생해 변수가 undefined로 평가된다.
  • 호이스팅이란 var 선언문이나 function 선언문 등 모든 선언문이 해당 Scope의 선두로 옮겨진 것처럼 동작하는 특성을 말한다. 즉, 자바스크립트는 모든 선언문(var, let, const, function, function, class)이 선언되기 이전에 참조 가능하다.

Function 생성자 함수

  • 기본 제공하는 빌트인 함수 Function 생성자 함수에 매개변수 목록과 함수 몸체를 문자열로 전달하면서 new 연산자와 함께 호출하면 함수 객체를 생성해서 반환한다.
    • 생성자 함수 : 객체를 생성하는 함수를 말한다.
  • 이 방식은 일반적이지 않으며 바람직한 방법도 아니다. (클로저생성하지 않음, 함수 선언문이나 함수 표현식과 다르게 동작)

화살표 함수

  • function 키워드 대신 화살표 ⇒ 를 사용해 간략한 방법으로 함수를 선언할 수 있다.
  • 익명함수로 정의한다.
const add = (x,y) => x+y;
add(2,5);//7
  • 기존 함수와 this 바인딩 방식이 다르고 prototype프로퍼티가 없으며 arguments 객체를 생성하지 않는다.

함수 호출

매개변수와 인수

  • 함수를 실행하기 위해 필요한 값을 매개변수(parameter)를 통해 인수(argument)를 전달한다.
  • 인수는 값으로 평가될 수 있는 표현식이어야 한다. 인수는 함수를 호출할때 지정하며, 개수와 타입에 제한이 없다.
  • 매개변수는 함수를 정의할 때 선언한다. 함수 몸체 내부에서 변수와 동일하게 취급된다. 외부에서는 참조할 수 없다. (매개변수의 스코프는 함수 내부)
  • 매개변수보다 인수의 개수가 부족해도 에러는 나지 않는 대신 인수가 할당되지 않는 매개변수의 값은 undefined 이다. 초과된 경우는 무시

인수 확인

  • 자바스크립트 함수는 매개변수와 인수의 개수가 일치하는지 확인하지 않는다.
  • 자바스크립트는 동적 타입 언어다. ⇒ 매개변수의 타입을 사전에 지정할 수 없다.
    • 함수를 정의할때 적절한 인수가 전달되었는지 조건으로 확인할 필요가 있다.
    • 정적 타입을 선언할 수 있는 타입스크립트를 사용해 부적절한 호출을 방지할 수 있다.
    • 단축평가나 매개변수 기본값을 사용하면 인수 체크 및 초기화를 간소화 할 수 있다.

매개변수의 최대 개수

  • 매개변수의 최대 개수에 대해 명시적으로 제한하고 있진 않지만 가급적 작게 만드는게 좋다. *3개 이상을 넘지 않는 것을 권장한다.
  • 매개변수는 순서에 의미가 있다.
  • 객체를 인수로 사용하는 경우에는 프로퍼티 키만 정확히 지정하면 매개변수의 순서를 신경 쓰지 않아도 된다.
    • 다만, 외부에서 함수 내부로 전달한 객체를 내부에서 변경하면 외부의 객체가 변경되는 side effect가 발생하는 것을 주의한다.

반환문

  • 함수는 return 키워드와 표현식(반환값)으로 이뤄진 반환문을 사용해 실행 결과를 함수 외부로 반환할 수 있다.
  • 2가지 역할
    • 함수의 실행을 중단하고 함수 몸체를 빠져나간다. 뒤에 코드가 더 있어도 무시된다.
    • return 키워드 뒤에 오는 표현식을 평가해 반환한다. 반환문을 생략하면 암묵적으로 undefined가 반환된다.

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

  • 매개변수를 통해 전달받은 원시 타입 인수와 객체 타입 인수를 함수 몸체에서 변경시
    • 원시 타입 인수는 원시값의 원본을 변경하는 어떠한 부수 효과도 발생하지 않는다.
    • 객체 타입 인수는 참조값이 복사되어 매개변수에 전달되어 함수 몸체에서 변경할 경우 원본 객체가 변경되는 부수 효과가 발생한다.
  • 원본 객체의 변경을 추적하는 것은 어려워진다. ⇒ 객체를 “불변 객체”로 만들어서 사용한다.
    • 객체를 원시값처럼 변경 불가능한 값으로 동작하게 만드는 것
    • 깊은 복사를 통해 새로운 객체를 생성하고 재할당을 통해 교체한다.

다양한 함수의 형태

즉시 실행 함수

  • 함수의 정의와 동시에 즉시 호출되는 함수를 즉시 실행 함수(IIFE)라고 한다.
  • 단 한번만 호출되고 다시 호출할 수 없다.
(function () {
	var a = 3;
	var b = 5;
	return a * b;
}());
  • 즉시 실행 함수도 일반 함수처럼 값을 반환할 수 있고 인수를 전달할 수도 있다.
  • 즉시 실행 함수 내에 코드를 모아 두면 변수나 함수 이름의 충돌을 방지할 수 있다. (전역 변수의 사용을 억제하는 방법)

재귀 함수

  • 함수가 자기 자신을 호출하는 것을 재귀 호출이라 한다. 재귀 함수는 자기 자신을 호출하는 것을 말한다.
  • 반복 처리를 위해서 사용된다.
    • 반복문 없이 구현 가능
// 팩토리얼
// 팩토리얼(계승)은 1부터 자신까지의 모든 양의 정수의 곱이다.
// n! = 1 * 2 * ... * (n-1) * n
function factorial(n) {
  if (n < 2) return 1;
  return factorial(n - 1) * n;
}

console.log(factorial(0)); // 1
console.log(factorial(1)); // 1
console.log(factorial(2)); // 2
console.log(factorial(3)); // 6
console.log(factorial(4)); // 24
console.log(factorial(5)); // 120
console.log(factorial(6)); // 720
  • 재귀함수는 자신을 마한 재귀 호출할 수 있어 반드시 탈출 조건을 만들어야 한다.
  • 무한 반복과 스택 오버플로 에러를 발생할 수 있어 주의해서 사용해야 한다.

중첩 함수

  • 함수 내부에 정의된 함수를 중첩 함수 또는 내부 함수라 한다.
  • 중첩 함수를 포함하는 함수는 외부 함수라 한다.
  • 중첩함수는 외부함수 내에서만 호출할 수 있고 스코프, 클로저와 깊은 관련이 있다.

콜백 함수

  • 함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수를 콜백 함수라고 한다.
  • 매개변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수를 고차 함수라고 한다.
  • 콜백 함수는 함수 외부에서 고차 함수 내부로 주입하기 때문에 자유롭게 교체할 수 있는 장점(고차 함수는 콜백 함수를 자신의 일부분으로 합성한다.)
  • 콜백 함수는 고차 함수에 의해 호출되며 이때 고차 함수는 필요에 따라 콜백 함수에 인수를 전달할 수 있다.
  • 콜백 함수를 전달받는 함수가 자주 호출된다면 함수 외부에서 콜백 함수를 정의한 후 함수 참조를 고차 함수에 전달하는 편이 효율적이다.
function repeat(n,f) {
	for(var i=0;i<n;i++) f(i);
}

//콜백함수 정의
var logOdds = function (i) {
	if(i%2) console.log(i); 
};

//고차함수에 함수 참조를 전달한다.
repeat(5, logOdds);
  • 비동기 처리, 이벤트 처리, 고차함수에 중요하게 사용된다.

순수함수와 비순수함수

  • 함수형 프로그래밍에서는 어떤 외부 상태에 의존하지도 않고 변경하지도 않는 부수효과가 없는 함수를 “순수 함수”라 한다.
  • 이와 달리 외부 상태에 의존하고 상태를 변경하는 부수효과가 있는 함수를 “비순수 함수”라 한다.

<순수함수>

  • 동일한 인수가 전달되면 언제나 동일한 값을 반환하는 함수
  • 순수함수는 일반적으로 최소 하나 이상의 인수를 전달받는다. 순수함수는 인수의 불변성을 유지한다.
  • 어떤 외부 상태에도 의존하지 않으며 함수의 외부 상태를 변경하지 않는다.

<비순수함수>

  • 외부 상태에 의존하고 상태도 변경할 수 있는 함수
  • 함수 내부에서 외부 상태를 직접 참조하지 않더라도 매개변수를 통해 객체를 전달받으면 비순수 함수가 된다.
  • 외부 상태를 변경하면 상태 변화를 추적하기 어려워진다. 복잡성 증가

<함수형 프로그래밍>

  • 함수형 프로그래밍은 순수함수와 보조 함수의 조합을 통해 외부 상태를 변경하는 부수 효과를 최소화해서 “불변성”을 지향하는 프로그래밍 패러다임이다.
  • 순수 함수를 통해 부수 효과를 최대한 피하고 프로그래밍의 안전성을 높인다.

0개의 댓글