즉시 실행 함수(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
으로 처리가 가능하다면 그게 최선일 것 같은데, 나는 이런 경우가 생겨 기록해둔다.