티스토리 뷰

Javascript

#8 IIFE(즉시호출함수표현식)

심재철 2019. 7. 29. 11:28

https://www.notion.so/simsimjae/8-IIFE-940e8c79379c4b49afdf63bf6867a81a

불러오는 중입니다...

함수 선언문

function sayHi() { alert("Hello, World!"); } sayHi();

위에서 sayHi 함수는 함수 선언문(statement)방식으로 만들어진 함수이다. 문장이기 때문에 함수명을 생략할수없다.

함수 표현식

var msg = "Hello, World!"; var sayHi = function() { alert(msg); }; sayHi();

반면 위와 같이 함수를 값으로써 취급하는 함수표현식 방식으로도 함수를 만들수있다.

또한, 함수표현식은 값으로 취급될수 있기 때문에 함수의 이름이 없어도 된다.

기명 함수 표현식

var fibo = function fibonacci() { fibonacci();// 여기서 fibonacci() 함수를 호출할 수 있습니다. // 이 함수 표현식이 이름을 갖고 있기 때문입니다. } // 여기서 fibonacci()를 호출하면 실패합니다. 하지만 fibo()는 동작합니다.

IIFE 즉시함수호출표현식

!function() { alert("Hello from IIFE!"); }(); // "Hello from IIFE" 메시지를 보여줍니다.

  • 자바스크립트는 위 코드를 해석하기 시작한다. !가 있는걸 본다.
  • !뒤에 어떤게 오든지 무조건 뒷부분을 표현식으로 해석하려고 한다.
  • 뒤에 함수가 정의되어 있지만 이것을 문장으로 해석하지 않고 표현식으로 해석한다.
  • 그래서 저런 문법에도 함수가 정상적으로 실행되는것이다.
  • !가 아니라 + - 등 1진연산자 어떤걸 갖다 붙여도 정상 실행되는것을 확인할수있다.
  • 또한 이 함수는 생명을 갖자마자 실행되고 바로 죽어버린다.
  • !의 역할은 뒤에 나오는 함수 문장을 함수 표현식으로 만들어버리는것이다.

또다른 IIFE

void function () { alert("Hello from IIFE!"); }();

  • void는 위에서 1진연산자와 마찬가지로 뒤에 나오는 것을 무조건 표현식으로 해석하게 만든다.
  • 주황색 부분이 표현식이 되기 때문에 () 함수 호출 문법으로 바로 호출이 가능했던것이다.

IIFE의 핵심은 함수를 식으로 변환한뒤, 바로 실행하는것이다.

IIFE의 두가지 방법

// 방법 1 (function () { alert("I am an IIFE!"); }()); // 방법 2 (function () { alert("I am an IIFE, too!"); })();

  • 빨간색 부분이 괄호()에 의해 표현식으로 취급되기 때문에 위와 같은 문법이 가능해지는것이다.
  • 방법1에서 괄호로 감싸주지 않으면 에러가 난다. 괄호가 없다면 저건 그냥함수 선언문이기 때문이다. 괄호로 감싸주었기 때문에 함수가 표현식이 되어 즉시 호출이 가능해진것이다.
  • 방법2에서도 마찬가지로 빨간색부분이 함수 표현식이 되어 리턴되고 그 리턴된 함수표현식을 바로 실행하는 구조이다.
  • 결론은 즉시함수호출표현식을 만드려면 함수를 괄호로 감싸서 표현식으로 만들어줘야한다.
  • 둘중, 어느것을 사용해도 문제 없으나 2번으로 된 코드를 많이 보았다.

올바르지 않은 IIFE 방법

// 유효하지 않은 IIFE function nonWorkingIIFE() { // 이제 왜 앞뒤로 괄호가 필요한지 알게 될 것입니다. // 괄호 없이는 그냥 함수 정의입니다. 표현식이 아닙니다. // 문법 에러가 날 것입니다. }(); function () { // 여기서도 문법 에러가 날 것입니다. // 1. 함수선언문에는 이름이 반드시 필요, 2.함수 선언문은 즉시 호출할수없음. 값이 아니라서 }();

IIFE의 활용 - private변수

(function IIFE_initGame() { // IIFE 밖에서는 접근할 수 없는 Private 변수들입니다. var lives; var weapons; init(); // IIFE 밖에서는 접근할 수 없는 Private 함수입니다. function init() { lives = 5; weapons = 10; } }());

  • 하지만 반대로 IIFE내부에서 외부로는 접근이 가능하다.
  • 이렇게 하면 자바스크립트의 전역 스코프를 건드리지 않기 때문에 이름충돌 가능성을 줄여준다.
  • 제이쿼리등 대부분의 자바스크립트 라이브러리들이 위와 같은 방식으로 네임스페이스 충돌 방지와 private변수 선언을 하고 있다.

값을 리턴하는 IIFE

var result = (function () { return "From IIFE"; }()); alert(result); // "From IIFE" 메시지를 출력합니다.

  • 만약 즉시 호출 함수의 리턴값이 필요없다면 !, +, void와 같은 방식을 사용해도 된다.
  • 하지만, 리턴값이 필요하다면 반드시 위와 같은 즉시호출함수가 필요하다.

매개변수를 받는 IIFE

(function IIFE(**msg**, **times**) { for (var i=1; i<=times; i++){ console.log(msg); } }(**"Hello!", 5**));

  • 괄호로 감싼 방식의 즉시호출함수는 위와같이 매개변수를 전달할수도 있다.
  • 그러니까 왠만하면 이 방식으로 즉시호출함수를 만들도록 하자. 굳이 !, +, void 방식을 쓸필요가 없다.

IIFE의 장점

(function($, global, document) { // jQuery를 위해 $를 사용하고, window를 위해 global을 사용합니다. }(jQuery, window, document));

  • 제이쿼리에서도 즉시호출함수를 매우 잘 활용하고 있다.
  • document를 즉시호출함수 안으로 넘기고 있다.
  • 만약에 매개변수로 넘기지 않고 document의 속성들을 찾으려고 하면 스코프 체인의 맨 끝에 있는 전역객체(window)에 도달할때까지 그 속성을 찾지 못할것이다.
  • 하지만 우리는, 매개변수로 document를 넘겼으므로 바로 document의 속성을 찾을 수 있다.
  • 또한, 얼마든지 매개변수의 이름을 바꿀 수 있다. jQuery → $ window → global

자바스크립트 모듈 패턴 : 클래식버전

var Sequence = (function sequenceIIFE() { // 현재 counter 값을 저장하기 위한 Private 변수 var current = 0; // IIFE로 부터 반환 받는 객체 return { getCurrentValue: function() { return current; }, getNextValue: function() { current = current + 1; return current; } }; }());

  • sequenceIIFE 함수는 문장으로 선언되었지만 괄호 () 안에 있으므로 표현식으로 취급된다.
  • current 변수는 IIFE 내부에서만 접근할 수 있는 private 변수이다.
  • IIFE에서 객체를 리턴하고 있는데 그 객체는 두가지 메소드 getCurrentValue, getNextValue를 가지고 있다.
  • 이 메소드에서만 current변수에 접근할수 있다. IIFE외부에서는 current에 접근이 불가능하다.
  • 마치, 클래스를 선언하고 멤버변수를 private 멤버함수를 public으로 선언해서 사용하는것과 똑같은 방식이다.

IIFE : 괄호 생략 버전

var result = funciton() { return "From IIFE!"; }();

  • 이 코드를 처음봤을때 이건 문장인가, 식인가 혼란스러웠다.

  • =연산자 오른쪽에 나왔으니까 값으로 취급되어야 하니까 식인가?

  • function 키워드로 시작했으니까 문장인가?

  • 결론은 식으로 해석된다. 왜냐면, 자바스크립트 엔진은 function 키워드를 문장으로 해석하지 않는다. 따라서, 해당 위치는 식이 와야하는것으로 알고 그렇게 해석한다.

  • 즉 위의 함수는 괄호가 빠진 즉시 호출 함수이며 다음 코드와 같다.

    var result = (funciton() { return "From IIFE!"; })();

하지만 가독성을 위해서 괄호 생략 버전의 IIFE는 지양하는것이 좋다. 다른사람들이 보편적으로 알고 있는 IIFE를 사용해야 서로가 코드를 쉽게 공유 할 수 있다.

IIFE를 사용하는 이유는 전역 스코프 오염을 방지하여 버그를 줄이는데에 있다. 코드를 더 이쁘고 정렬하기 위해서 사용하는것이 아니다.

'Javascript' 카테고리의 다른 글

#9 이벤트 루프  (0) 2019.09.25
Event Emitter를 언제 사용해야 할까?  (0) 2019.09.15
#7 문장 vs 표현식  (3) 2019.07.29
#7 문장 vs 표현식 - 유튜브 expression vs statement번역  (1) 2019.07.29
#6 함수와 블록스코프  (1) 2019.07.29
댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함