본문 바로가기
Programming/자바스크립트

[자바스크립트] 즉시 실행 함수(IIFE)

by 코딩하는 랄로 2023. 10. 27.
728x90

즉시 실행 함수

즉시 실행 함수란 이름 그대로 함수의 정의와 동시에 즉시 호출되어 실행되는 함수이다. Immediately Invoked Function Expression의 약자인 IIFE라고도 부른다.

 

즉시 실행 함수는 단 한번만 실행되며, 다시 호출할 수 없다. 사용하는 방법으로는 함수를 그룹 연산자로 감싼다음 함수를 호출하면 된다.

// 익명 IIFE
// 일반 함수
(fuction () {
    console.log('일반 함수 익명 IIFE');
}()); // 일반 함수 익명 IIFE


// 화살표 함수 가능
(() => {
    console.log('화살표 함수 익명 IIFE');
}()); // 화살표 함수 익명 IIFE


// 기명 IIFE
(fuction iife() {
    console.log('기명 IIFE');
}()); // 기명 IIFE

iife(); //ReferencedError : iife is not defined

 

즉시 실행 함수는 한 번 호출되고 다시 호출 할 수 없기 때문에 기명 함수 선언을 통해 이름을 선언해주어도 실행이 끝나는 동시에 없어지기 때문에 해당 이름을 통해 함수를 재호출시 에러가 발생한다.

 

그렇기 때문에, 일반적으로는 즉시실행함수는 일반함수로 사용하지만 기명 함수로 사용하여도 된다.

 

 

 

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

즉시 실행 함수를 그룹연산자로 감싸지 않고 사용한다면 다음과 같은 에러를 볼 수 있을 것이다.

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

 

문법의 에러가 발생했고, function 구문에서 함수의 이름이 필요함을 알려주고 있다. 자바스크립트 엔진이 해당 함수 구문을 함수 선언문으로 해석하고 익명함수를 사용할 수 없으니 이름이 필요함을 알려주는 것이다.

 

그렇다면 이름을 넣게 되면 어떻게 될까?

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

 

또 문법 에러가 발생한다!! 이번에는 기대하지 않던 토근 ')'이 있다고 알려주고 있다. 이는 자바스크립트 엔진이 함수 선언문이 끝나는 중괄호({}) 뒤에 오는 소괄호를 호출 연산자가 아닌 그룹 연산자로 해석하기 때문에 발생하는 문장이다. 즉, 다음과 같이 해석하는 것이다.

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

 

그룹 연산자로 해석하기 때문에 소괄호 안에 피연산자(표현식)이 와야 하는데 기대하지 않던 ')'가 바로 와서 위와 같은 에러를 띄우는 것이다. 그렇기 때문에 우리는 자바스크립트 엔진에게 해당 함수를 즉시 실행 함수로 사용한다고 말해주어야 한다.

 

이를 위해서 사용되는 즉시 실행 함수의 리터럴이 그룹 연산자인 것이다. 자바스크립트 엔진은 그룹 연산자 안의 함수로 함수 객체를 생성하게 되고 이렇게 생성한 객체를 바로 호출할 수 있게 되는 것이다.

 

그룹 연산자 이외에도 함수가 아래와 같이 값으로 평가되는 문맥이라면 자바스크립트 엔진은 함수 객체를 생성하게 되고 즉시 실행 함수로서 호출할 수 있다.

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

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

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

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

 

 

 

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

전역 변수의 사용 억제

전역 변수는 아래와 같은 문제점을 가지고 있다.

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

그렇기 때문에 전역 변수의 사용은 억제할 수 있는 것이 좋다. 하지만 함수의 선언은 전역 변수로서 지정이 되기 때문에 재사용성이 떨어지는 함수를 계속해서 선언해주는 것은 자제 해주는것이 좋다.

 

즉시 실행 함수는 지역 변수로서 지정되어 호출이 끝나는 즉시 사라지기 때문에 변수의 충돌을 피할 수 있어 라이브러리 등에 자주 사용된다.

 

 

정보의 은닉

즉시 실행 함수는 클로저를 만들 때 사용된다. 클로저는 중첩 함수가 상위 스코프의 식별자를 참조하고 있고 중첩 함수가 외부 함수보다 더 오래 유지되는 경우를 말한다. 그렇기 때문에 클로저는 상태가 의도치 않게 변경되지 않도록 안전하게 은닉하고 특정 함수에게만 상태 변경을 허용하여 상태를 안전하게 변경하고 유지하기 위해 사용한다.

 

즉시실행함수는 외부에서 접근 할 수 없는 자체적인 스코프를 가지고 있어 내부 변수를 외부로부터 private하게 보호 할 수 있다는 장점이 있기 때문에 클로저를 만들 때 유용하게 사용이 된다.

 

 

 

즉시 실행 함수의 활용

한번의 사용만 필요한 함수

변수의 초기화와 관련된 함수는 한번만 사용해도 되기 때문에 즉시 실행 함수로 구현하는 것이 좋다.

let isAdult;

((age) => {
    isAdult = (age >= 20)
})(20);

console.log(isAdult); //true

 

 

렉시컬 환경을 공유하는 클로저 생성 => 모듈

// 함수를 반환하는 고차 함수
// 이 함수는 카운트 상태를 유지하기 위한 자유 변수 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

 

위의 코드의 경우 고차 함수 여러번 호출되면 함수 실행 컨텍스트가 여러 개 생기게 되고 각각의 실행 컨텍스트마다 참조하는 변수(counter)가 개별로 존재하게 된다. 즉, counter함수를 호출할 때마다 새로운 counter 변수가 계속 생겨나는 것이다.

 

같은 변수를 공유하기 위해서는 고차 함수가 한번 실행되어야 하고, 그렇게 되면 변수 counter는 하나만 존재하게 된다. 이를 클로저와 보조 함수를 이용하여 증가시키고 감소시킬 수 있게 되는 것이다.

 

자바스크립트 모듈을 만들 때에 위의 개념을 활용하여 만들게 된다.

 

728x90