즉시실행함수라는 것이 있다. 보통 아래와 같이 생겼다.
(function() {
// my special code
})();
왜 필요할까? 언제 쓸까? 이것에 대한 해답은 하나로 정해져 있지 않다.
JS를 처음 배웠을 때 이 즉시실행함수에 대해 바로 이해하기 어려웠다. JS 초급을 벗어나게 되면서 점점 JS의 고급화된 문법을 배우기 시작했고 거기에서
최근 들어서 더욱 쓸 일이 많아졌다고 생각한다.
실제 코드예시
즉시실행함수는 어디에서 찾아볼 수 있을까? 다음은 jquery.hammer.js의 코드이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | (function(factory) { if (typeof define === 'function' && define.amd) { define(['jquery', 'hammerjs'], factory); /*....생략 */ // extend the emit method to also trigger jQuery events Hammer.Manager.prototype.emit = (function(originalEmit) { return function(type, data) { originalEmit.call(this, type, data); $(this.element).trigger({ type: type, gesture: data }); }; })(Hammer.Manager.prototype.emit); })); | cs |
기본 사용방법
일반적으로 anonymous함수(익명 함수)를 실행 할 때는 참조변수를 할당 한 후에 ()를 붙여서 실행한다.
이게 보통 우리가 사용하는 방식이다.
const a = function() {};
a();
IIFE는 이렇게 사용한다.
(function(){...})()
//이렇게도 사용할 수 있다.
(function(){...}())
하지만 보통 첫번째 방법을 많이 사용하는 것 같다.
ES6의 row function을 사용한다면 이렇게 나타낸다.
(() => {
/* */
})();
사용하는 이유
왜 사용할까? 전문적으로 말하면 전역변수에 접근하지 못하게 하기 위함이다.
아래와 같이 더 쉽게 설명해보고자 한다.
const myFunc = function() {
const content = "Hello World";
console.log(content);
};
이제 myFunc는 해당 Script나 해당 script를 참조하는 html의 어떤 곳에서든 접근할 수 있다.
하지만 코드가 길어지고 규모가 방대해 진다면 이름이 동일한 함수나 변수를 사용해야 할 일이 생길 지도 모른다.(가능한 한 피하는 편이 좋지만)
특히나 외부 라이브러리를 이용한다면 내가 사용하는 이 변수이름이 외부 라이브러리의 이름과 동일한 일이 생길 수도 있지 않은가?
기본적으로 함수표현은 함수를 정의, 변수에 함수를 저장하고 실행한다. 하지만 즉시실행함수는 이름 그대로 함수를 정의하자마자 바로 호출하게 된다.
즉시실행함수를 이용하여 버그 바로잡기
즉시실행함수에 대한 내용은 다른 블로그에도 잘 작성되어 있다. 그래서 나는 즉시실행함수를 통하여 오류를 바로잡는 예제를 통해 살펴보고자 했다.
function createButtons() {
for (var i = 1; i <= 5; i++) {
var body = document.getElementsByTagName("BODY")[0];
var button = document.createElement("BUTTON");
button.innerHTML = "Button " + i;
button.onclick = function() {
alert("This is Button " + i);
};
body.appendChild(button);
}
}
createButtons();
위의 코드를 보면 해당 버튼을 클릭할 경우 “This is Button 클릭한 숫자“를 출력할 것으로 생각할 수도 있다.
하지만 실제로 눌러보면 그렇지 않다.
모두가 button 6으로 뜬다. 그 이유는 무엇일까?
크롬 개발자 도구를 이용하여 디버깅 해보았다.
위에서 i 이터레이션이 i<=5
까지이고 i++
이기 때문에 i=6까지 실행이 된다.
또한 이터레이션 값이 계속 바뀌기 때문에 onclick
메소드에 있는 i 값은 계속 바뀌게 된다.
즉 코드를 올바르게 고치려면 onclick
메소드에 안에 있는 변수 i
가 외부 영향을 받지 않게 만들어야 한다.
그래서 IIFE를 통해 i값을 캡슐화 시켜 독립된 값으로 만드는 것이다. IIFE를 통해 올바르게 고쳐보았다.
function createButtons() {
for (var i = 1; i <= 5; i++) {
var body = document.getElementsByTagName("BODY")[0];
var button = document.createElement("BUTTON");
button.innerHTML = "Button " + i;
(function(num) {
button.onclick = function() {
alert("This is Button " + num); //이제 num은 외부의 i값과 상관없이 항상 고정된 값을 가리킨다.
};
})(i);
body.appendChild(button);
}
}
아니면 이렇게 외부 함수로 빼는 방법이 있다. 사실 이게 더 가독성이 좋다. 더 추천하는 방법이다.
function createButtons() {
for (var i = 1; i <= 5; i++) {
var body = document.getElementsByTagName("BODY")[0];
var button = document.createElement("BUTTON");
button.innerHTML = "Button " + i;
addClickFunctions(i, button);
body.appendChild(button);
}
}
function addClickFunctions(num, button) {
button.onclick = function() {
alert("This is Button " + num);
};
}