IIFE
즉시 실행 함수 표현(IIFE, Immediately Invoked Function Expression) 은 정의되자마자 즉시 실행되는 Javascript Function 를 말한다. IIFE라는 이름은 Ben Alman이 블로그에서 처음으로 시작되었습니다.
(function () {
// …
})();
(() => {
// …
})();
(async () => {
// …
})();
이는 Self-Executing Anonymous Function 으로 알려진 디자인 패턴이고 크게 두 부분으로 구성됩니다.
-
Grouping Operator
()
안에 어휘 범위로 둘러싸인 익명함수입니다. 이는 전역 스코프에 불필요한 변수를 추가해서 오염시키는 것을 방지할 수 있을 뿐 아니라 IIFE 내부안으로 다른 변수들이 접근하는 것을 막을 수 있는 방법입니다. -
두 번째 부분은 즉시 실행 함수를 생성하는 괄호
()
입니다. 이를 통해 JavaScript 엔진은 함수를 즉시 해석해서 실행합니다.
사용 예시
>전역 이름공간을 오염시키는 것을 방지
애플리케이션은 다양한 소스 파일의 많은 함수와 전역 변수를 포함할 수 있기 때문에, 전역 변수의 수를 제한하는 것이 중요합니다. 필요 없는 초기화 코드가 있는 경우, IIFE 패턴을 사용할 수 있습니다. 코드를 다시 재사용하지 않을 것이기 때문에 이 경우 IIFE를 사용하는 것이 함수 선언 또는 함수 표현식을 사용하는 것보다 더 좋습니다.
(() => {
// 초기화 코드
let firstVariable;
let secondVariable;
})();
// firstVariable와 secondVariable은 이 함수 실행 후에 사용할 수 없습니다.
비동기 함수 실행
async
IIFE를 사용하면 top-level await이 없는 이전 브라우저 및 JavaScript 런타임에서도 await
및 for-await
을 사용할 수 있습니다.
const getFileStream = async (url) => {
// 구현
};
(async () => {
const stream = await getFileStream("https://domain.name/path/file.ext");
for await (const chunk of stream) {
console.log({ chunk });
}
})();
모듈 패턴
우리는 또한 IIFE를 사용하여 비공개 및 공개 변수와 메서드를 생성할 수 있습니다. 더 정교한 모듈 사용을 위해, 패턴 및 IIFE의 다른 사용에 대해서는 Addy Osmani의 Learning JavaScript Design Patterns라는 책을 볼 수 있습니다.
const makeWithdraw = (balance) =>
((copyBalance) => {
let balance = copyBalance; // This variable is private
const doBadThings = () => {
console.log("I will do bad things with your money");
};
doBadThings();
return {
withdraw(amount) {
if (balance >= amount) {
balance -= amount;
return balance;
}
return "Insufficient money";
},
};
})(balance);
const firstAccount = makeWithdraw(100); // "I will do bad things with your money"
console.log(firstAccount.balance); // undefined
console.log(firstAccount.withdraw(20)); // 80
console.log(firstAccount.withdraw(30)); // 50
console.log(firstAccount.doBadThings); // undefined; this method is private
const secondAccount = makeWithdraw(20); // "I will do bad things with your money"
console.log(secondAccount.withdraw(30)); // "Insufficient money"
console.log(secondAccount.withdraw(20)); // 0
ES6 이전의 var가 있는 For 루프
ES6 및 블록 범위에서 let and const문이 도입되기 전에 과거 코드에서 다음과 같은 IIFE 사용을 볼 수 있습니다. var문을 사용하면 함수 범위와 전역 범위만 가지게 됩니다. 버튼 0, 버튼 1이라는 텍스트가 있는 2개의 버튼을 만들고 싶은 예제를 생각해보면, 다음 코드는 작동하지 않습니다.
for (var i = 0; i < 2; i++) {
const button = document.createElement("button");
button.innerText = `Button ${i}`;
button.onclick = function () {
console.log(i);
};
document.body.appendChild(button);
}
console.log(i); // 2
클릭하면 i
가 전역 변수이고, 마지막 값이 2이므로 2로 로그를 보여주게 됩니다. ES6 이전에 이 문제를 해결하려면 IIFE 패턴을 사용할 수 있습니다.
for (var i = 0; i < 2; i++) {
const button = document.createElement("button");
button.innerText = `Button ${i}`;
button.onclick = (function (copyOfI) {
return function () {
console.log(copyOfI);
};
})(i);
document.body.appendChild(button);
}
console.log(i); // 2
클릭하면, button 0과 1이 0과 1이라고 출력합니다. 변수 i는 전역적으로 정의됩니다. let문을 사용하면 간단하게 다음과 같이 할 수 있습니다.
for (let i = 0; i < 2; i++) {
const button = document.createElement("button");
button.innerText = `Button ${i}`;
button.onclick = function () {
console.log(i);
};
document.body.appendChild(button);
}
console.log(i); // Uncaught ReferenceError: i is not defined.
클릭하면, button 0과 1이 0과 1이라고 출력합니다.