LHJ

I'm a FE developer.

6.6 함수 표현식과 익명 함수

03 May 2020 » js_lj

지금까지는 함수 선언만 봤습니다.
함수를 선언하면 함수에 바디식별자가 모두 주어집니다.
자바스크립트는 익명 함수(anonymous function) 도 지원합니다.
익명 함수에서는 함수에 식별자가 주어지지 않습니다.

함수에 식별자가 없다는 말을 보고 어리둥절했을 수도 있습니다.
식별자가 없다면, 도대체 어떻게 호출해야 할까요?
답은 함수 표현식(function expression) 에 있습니다.
우리는 표현식이 값이 되고, 함수 역시 값이 된다는 것을 알고 있습니다.
함수 표현식은 함수를 선언하는 한 가지 방법일 뿐이며, 그 함수가 익명이 될 수도 있을 뿐입니다.
함수 표현식은 식별자에 할당할 수도 있고 즉시 호출할 수도 있습니다.

즉시 호출하는 함수 표현식(IIFE, immediately invoked function expression)이라고 부릅니다.
7장에서 설명합니다.

함수 표현식은 함수 이름을 생략할 수 있다는 점을 제외하면 함수 선언과 문법적으로 완전히 같습니다.
함수 표현식을 쓰고 그 결과를 변수에 할당하는 예제를 봅시다.
이 예제는 결과적으로 함수 선언과 동등합니다.

const f = function() {
	// ...
};

결과는 여태까지 했던 대로 함수를 선언한 것과 마찬가지입니다.
식별자 f가 이 함수를 가리킵니다.
일반적인 함수 선언과 마찬가지로 f()로 이 함수를 호출할 수 있습니다.
차이점은 먼저 함수 표현식으로 익명 함수를 만들고 그 함수를 변수에 할당했다는 겁니다.

익명 함수는 어디든지 쓸 수 있습니다.
다른 함수나 메서드의 매개변수로 넘길 수도 있고, 객체의 함수 프로퍼티가 될 수도 있습니다.
책 전체에 걸쳐 이런 방법을 사용할 겁니다.

앞에서 함수 표현식에서는 함수 이름을 생략할 수 있다고 했습니다.
그러면 함수에 이름을 정하고 다시 변수에 할당하면 어떻게 될까요?
그리고 그렇게 한다면 이유는 무엇일까요?
다음 예제를 보십시오.

const g = function() {
	// ...
}

이런 식으로 함수를 만들면 이름 g에 우선순위가 있습니다.
그리고 함수 바깥에서 함수에 접근할 때는 g를 써야 하며, f로 접근하려 하면 변수가 정의되지 않았다는 에러가 생깁니다.
그렇다면 왜 이런 방법을 사용하는 걸까요?
함수 안에서 자신을 호출할 때 (재귀(recursion) 라고 합니다) 이런 방식이 필요할 수 있습니다.
다음 예제를 보십시오.

const g = function f (stop) {
	if(stop) console.log('f stopped');
	f(true);
};
g(false);

함수 안에서는 f를 써서 자기 자신을 참조하고, 함수 바깥에서는 g를 써서 함수를 호출합니다.
함수에 두 가지 이름을 붙이는 것이 좋을 이유는 없지만, 여기서 그렇게 한 이유는 이름 붙은 함수 표현식이 어떻게 동작하는지 명확하게 설명하기 위해서입니다.

함수 선언과 함수 표현식이 완전히 똑같이 보인다면, 자바스크립트는 둘을 어떻게 구분할까요?
차이가 있기는 한 걸까요?
답은 컨텍스트입니다.
함수 선언이 표현식으로 사용됐다면 그건 함수 표현식입니다.
표현식으로 사용되지 않았다면 함수 선언입니다.

이 차이는 다분히 이론적이며, 일반적으로는 이 차이에 대해 생각할 필요가 없습니다.
나중에 호출할 생각으로 함수를 만든다면 함수 선언을 사용하면 되고, 다른 곳에 할당하거나 다른 함수에 넘길 목적으로 함수를 만든다면 함수 표현식을 사용하면 됩니다.
복잡하게 생각할 필요는 없습니다.