[JavaScript] 즉시 실행 함수

hyowon·2021년 10월 5일
2

즉시 실행 함수

함수 정의와 동시에 즉시 호출되는 함수를 즉시 실행 함수(IIFE, Immediately Invoked Function Expression)라고 한다.

즉시 실행 함수는 단 한 번만 호출되며 다시 호출할 수 없다.


// 익명 즉시 실행 함수
(function () {
 var a = 3;
 var b = 5;
 return a * b;
}());


// 기명 즉시 실행 함수
(function foo() {
 var a = 3;
 var b = 5;
 return a * b;
}());

foo(); // ReferenceError: foo is not defined

기명 즉시 실행 함수의 경우 함수 이름이 함수 몸체에서만 유효한 식별자 이므로 함수를 다시 호출할 수 없다.

함수 이름이 없는 익명 함수를 사용하는 것이 일반적이다.

즉시실행함수를 그룹연산자(괄호)로 감싸는 이유

function () { // SyntaxError: Function statements require a function name
 // ...
}();

이 코드의 경우 자바스크립트 엔진이 함수 선언문으로 해석하는 문맥이다. 함수 선언문의 경우 함수 이름을 생략할 수 없어서 에러가 발생한다.

function foo() {
 // ...
}(); // SyntaxError: Unexpected token ')'

이 코드의 경우 자바스크립트 엔진이 암묵적으로 수행하는 세미콜론 자동 삽입 기능에 의해 함수 선언문이 끝나는 위치에 세미콜론이 추가된다.

function foo() {};(); 

추가된 세미콜론 뒤에 괄호는 함수 호출 연산자가 아니라 그룹 연산자로 해석되고 그룹 연산자의 피연산자가 없기때문에 에러가 발생한다.

그룹 연산자로 즉시 실행 함수를 감싸는 이유는 함수를 평가해서 함수 객체를 생성하기 위해서다.

그룹 연산자 안의 함수는 자바스크립트 엔진이 함수 리터럴로 해석하고 평가하여 함수 객체로 생성한다.


(function () {
 // ...
}());

(function () {
 // ...
})();

!function () {
 // ...
}();

+function () {
 // ...
}();

따라서 위와 같이 값으로 평가되는 문맥이라면 함수 객체가 생성되고 호출할 수 있게 된다. 일반적으로는 그룹연산자와 함께 사용한다.

즉시실행함수를 사용하는 이유

전역변수 사용을 억제하기 위해서

전역변수의 문제점

  • 전역 변수는 모든 코드가 전역변수를 참조하고 변경할 수 있기때문에 상태가 변경 될 수 있는 위험성이 높다.
  • 생명주기가 어플리케이션의 생명주기와 동일하기때문에 메모리 리소스도 오랜 기간 소비한다.
  • 스코프 체인의 종점에 위치하기 때문에 변수 검색 속도가 느리다
  • 자바스크립트는 파일이 분리 되어있다해도 하나의 전역 스코프를 공유하기때문에 같은 스코프 내에 전역변수나 전역함수가 예상치 못한 결과를 가져올 수 있다.

전역변수는 위와 같은 문제점이 있으므로 사용하지 않는 편이 좋다.
모든 코드를 즉시 실행 함수로 감싸면 모든 변수는 즉시 실행 함수의 지역 변수가 된다.
변수의 충돌을 피할 수 있어 라이브러리 등에 자주 사용된다.

정보 은닉을 위해서

즉시 실행 함수는 클로저를 만들때 사용된다.

클로저는 중첩 함수가 상위 스코프의 식별자를 참조하고 있고 중첩 함수가 외부 함수보다 더 오래 유지되는 경우를 말한다.

클로저는 상태가 의도치 않게 변경되지 않도록 안전하게 은닉하고 특정 함수에게만 상태 변경을 허용하여 상태를 안전하게 변경하고 유지하기 위해 사용한다.

렉시컬 환경을 공유하는 클로저를 만들기 위해서

// 함수를 반환하는 고차 함수
// 이 함수는 카운트 상태를 유지하기 위한 자유 변수 counter를 기억하는 클로저를 반환한다.
const counter = (function () {
  // 카운트 상태를 유지하기 위한 자유 변수
  let counter = 0;
  // 함수를 인수로 전달받는 클로저를 반환
  return function (predicate) {
    // 인수로 전달받은 보조 함수에 상태 변경을 위임한다.
    counter = predicate(counter);
    return counter;
  };
})();
// 보조 함수
function increase(n) {
  return ++n;
}
// 보조 함수
function decrease(n) {
  return --n;
}
// 보조 함수를 전달하여 호출
console.log(counter(increase)); // 1
console.log(counter(increase)); // 2
// 자유 변수를 공유한다.
console.log(counter(decrease)); // 1
console.log(counter(decrease)); // 0

이 코드의 경우 고차 함수가 여러번 호출되면 함수 실행 컨텍스트가 여러개 생겨서 실행 컨텍스트 마다 참조하는 변수가 개별로 존재하게 된다.

increase 함수와 decrease 함수가 변수를 공유하기 위해서는 고차 함수가 단 한번만 호출되어야 하므로 즉시 실행 함수를 사용해야한다.


참고
모던 자바스크립트 Deep Dive
https://dev.to/myk/8-what-is-iife-in-javascript-1bng

0개의 댓글