[JavaScript] 즉시 실행 함수(IIFE)

찐새·2023년 2월 14일
0

Javascript

목록 보기
7/11
post-thumbnail

즉시 실행 함수(IIFE, Immediatly Invoked Funcion Expression)는 정의하는 즉시 실행하는 함수이다.

일반 함수

일반적으로 ()() 형태이다. 첫 번째 괄호 안에 함수 표현식을 적고, 두 번째 괄호를 적으면 해당 함수를 즉시 실행한다. 매개변수가 있는 경우 두 번째 괄호 안에 입력한다.

(function foo() {
  console.log("foo")
}); // 실행되지 않음

(function foo() {
  console.log("foo")
})(); // foo

(function bar(str) {
  console.log(str)
})("bar"); // bar

(function (str) {
  console.log(str)
})("anonymous fn"); // anonymous fn 

(() => {
  console.log("anonymous arrow fn")
})(); // anonymous arrow fn 

일반 함수와 다르게 즉시 실행 함수를 연속적으로 사용할 때는 표현식 끝에 세미콜론(;)을 꼭 붙여야 한다. 그렇지 않으면 에러가 발생한다.

// no semi-colon
(function foo() {
  console.log("foo")
})() // foo

(function bar(str) {
  console.log(str)
})("bar") // TypeError: (intermediate value)(...) is not a function

// has semi-colon
(function foo() {
  console.log("foo")
})(); // foo

(function bar(str) {
  console.log(str)
})("bar"); // bar

익명 함수 내에 선언한 함수명은 블록 스코프가 익명 함수로 한정되었으므로 당연히 외부에서 호출할 수 없다.

(function foo() {
  console.log("foo")
});

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

익명 함수로 실행한 함수를 변수에 담아 재사용도 가능하다.

const temp = ((str) => {
  console.log("inner", str)
  return str
})("temp"); // inner temp

console.log("outer", temp); // outer temp

비동기 함수

async/await이나 Promise를 사용한 함수의 경우도 똑같이 사용할 수 있다. 더미 데이터 패치는 JSONplaceholder를 이용했다.

(async function (){
  const data = await fetch('https://jsonplaceholder.typicode.com/todos/1')
  console.log(data)
})();

// Response {status: 200, ok: true ...}

const x = async () => {
  return "inner x"
};

const a = new Promise((resolve)=>{
  resolve("inner a")
});

(async function main(){
  console.log(await a, await x());
})(); // inner a inner x 

함수를 return하는 비동기 함수를 변수에 할당하고 실행할 때 보통 then이나 await을 활용한다.

const x = async () => {
  const y = 5;
  return function (){
    console.log(y)
    return "x 안의 y"
  };
};

(async function main(){
  const z = x()
  z.then((z)=>console.log("then ",z()))
  const a = await x()
  console.log("await", a())
})();

만약 비동기 함수의 리턴값 함수를 변수에 할당하면서 then 대신 await을 사용한다면 이 역시 즉시 실행 함수 표현식으로 가능하다.

const x = async () => {
  const y = 5;
  return function () {
    console.log(y);
    return "x 안의 y";
  };
};

const a = new Promise((resolve) => {
  resolve(function () {
    return "a 안의 익명 함수";
  });
});

(async function main() {
  const z = x();
  console.log("await ", (await z)());
  console.log((await a)());
})();

/*
5
await x 안의 y
a 안의 익명 함수
*/

z에 할당된 함수를 (await z)()로, a가 리턴하는 함수를 (await a)()로 실행했다.

어디서 이렇게 사용하겠냐마는, 나는 React 컴포넌트에서 비동기 커스텀 훅을 받아와 useEffect 안에서 사용했다. 예를 들면 다음과 같다.

function App() {
  const temp = useFetchDateHook(); // 데이터 상태를 저장하는 함수를 리턴
  useEffect(()=>{
    (async function (){
      const data = await fetch('https://jsonplaceholder.typicode.com/todos/1')
      (await temp)(await data.json());
      })();
  },[])
  return (...)
}

비동기 커스텀 훅을 사용하고 싶지만 컴포넌트는 비동기 호출이 되지 않는다. 때문에 변수에 함수를 할당한 후 useEffect 내부의 async 즉시 실행 함수 안에서 커스텀 훅 함수를 await으로 처리했다.

물론 일반적인 async/await으로 처리가 가능하다면 그게 최선일 것 같은데, 나는 이런 경우가 생겨 기록해둔다.


참고
MDN docs - 함수
MDN docs - IIFE

profile
프론트엔드 개발자가 되고 싶다

0개의 댓글