티스토리 뷰


즉시실행함수 (Immediately-invoked function expression)


즉시실행함수에 이해하기 위해서 함께 알면 좋을것들

  • 자바스크립트 함수 : first-class object
  • 자바스크립트 Scope (function-level scope)
  • 함수 정의 ( 함수 선언식, 함수 표현식 )


자바스크립트에서 가장 큰 문제점 중의 하나는 글로벌 스코프에 정의된 것은 코드 내의 어디서든지 접근이 가능하다는 것입니다. 하지만, 외부에 공유되면 안되거나 공유될 필요가 없는 속성이나 메소드가 있습니다. 또한, 다른 스크립트 파일 내에서 동일한 이름으로 명명된 변수나 함수가 있을 경우 원치 않는 결과를 가져올 수 있습니다.

익명 함수표현식으로 함수를 하나 정의하고 실행해 보겠습니다. 그리고 외부에서 함수 내의 변수에 접근해 보겠습니다.


// 함수표현식에 의한 명시적인 함수호출
var app = function() {  
    console.log('함수 호출'); // "함수 호출" 출력
};
app();  

이번에는 익명 즉시실행함수로 함수를 정의해 보겠습니다.


// 즉시실행함수
(function() {
    console.log('함수 호출'); // "함수 호출" 출력
}());

위 두개의 코드는 동일한 동작을 수행합니다.

함수표현식은 함수를 정의하고, 변수에 함수를 저장하고 실행하는 일련의 과정을 거칩니다. 하지만, 즉시실행함수를 사용하면 이와 같은 과정을 거치지 않고 즉시 실행된다는 특징이 있습니다. 차이점이라면 단순히 함수를 괄호"()"로 랩핑한 게 전부입니다. 이런 함수를 즉시실행함수(IIFE)라 부릅니다.

이번에는 변수를 선언하고 이 변수에 즉시실행함수를 할당해 보겠습니다.


var app = (function() {  
    var privateVar = 'private';
    return {
        prop : privateVar
    };
}());
console.log(app.prop); // "private" 출력  

콘솔에는 "private" 라고 출력됩니다.

즉시실행함수 내에서 선언한 변수를 외부에서도 접근할 수 있음을 확인할 수 있습니다. 변수의 접근 범위가 함수 내부가 아닌 외부에서도 가능해진 것입니다. 이와 같이, 즉시실행함수는 변수의 스코프를 포함하는데 사용되며 외부에서 함수 내의 변수에 접근할 경우 이를 통제할 수 있습니다. 즉시실행함수는 글로벌 네임스페이스에 변수를 추가하지 않아도 되기 때문에 코드 충돌이 없이 구현할 수 있어 플러그인이나 라이브러리 등을 만들 때 많이 사용됩니다.

아래 두개의 코드는 기명 함수표현식과 즉시실행함수에서 파라미터를 전달하는 방법을 보여줍니다.


var buyCar = function(carName) {  
    // "내가 구매한 차는 sonata입니다." 출력
    console.log('내가 구매한 차는 ' + carName + '입니다.');
};
buyCar('sonata');

(function(carName) {
    // "내가 구매한 차는 sonata입니다." 출력
    console.log('내가 구매한 차는 ' + carName + '입니다.');
}('sonata'));

위 두개의 코드 블럭은 동일한 동작을 수행합니다. 또한, 앞서의 예제처럼 괄호"()"로 랩핑한 차이 밖에 없습니다.


과제


// 1. 함수 선언식
var hanq = a(); // alert 1

function a() {
 alert("1");
};

위 코드를 보면 함수선언식으로 함수가 정의되기 이전에 함수 호출이 가능하다. 함수 선언의 위치와는 상관없이 코드 내 어느 곳에서든지 호출이 가능한데 이것을 함수 호이스팅(Function Hoisting)이라 한다.

호이스팅이란 var 선언문이나 function 선언문 등을 해당 Scope의 맨 위로 옮기는 것을 말한다. 즉 자바스크립트는 코드를 실행하기 전에 var 선언문과 function 선언문을 해당 스코프의 맨위로 옮긴다.

함수선언식으로 정의된 함수는 자바스크립트 엔진이 스크립트가 로딩되는 시점에 바로 초기화하고 이를 VO(variable object)에 저장한다. 즉, 함수 선언, 초기화, 할당이 한번에 이루어진다. 그렇기 때문에 함수 선언의 위치와는 상관없이 소스 내 어느 곳에서든지 호출이 가능하다.

다음은 함수표현식으로 함수를 정의한 경우이다.


// 2. 기명 즉시실행함수 
var hanq = a(); // TypeError: a is not a function

(function a() {
 alert("1");
})();

// Douglas Crockford의 권장 표기법
(function a() {
 alert("1");
}());

함수선언식의 경우와는 달리 TypeError가 발생하였다. 함수표현식의 경우 함수 호이스팅이 아니라 변수 호이스팅이 발생한다.

변수 호이스팅은 변수 생성 및 초기화와 할당이 분리되어 진행된다. 호이스팅된 변수는 undefined로 초기화 되고 실제값의 할당은 할당문에서 이루어진다.

함수표현식은 함수선언식과는 달리 스크립트 로딩 시점에 변수 객체(VO)에 함수를 할당하지 않고 runtime에 해석되고 실행되므로 이 두가지를 구분하는 것은 중요하다.

JavaScript : The Good Parts의 저자이며 자바스크립트의 권위자인 더글러스 크락포드(Douglas Crockford)는 이와 같은 문제 때문에 함수표현식만을 사용할 것을 권고하고 있다. 함수 호이스팅이 함수 호출 전 반드시 함수를 선언하여야 한다는 규칙을 무시하므로 코드의 구조를 엉성하게 만들 수 있다고 지적한다.

또한 함수선언식으로 함수를 정의하면 사용하기에 쉽지만 대규모 애플리케이션을 개발하는 경우 인터프리터가 너무 많은 코드를 변수 객체(VO)에 저장하므로 애플리케이션의 응답속도는 현저히 떨어질 수 있으므로 주의해야 할 필요가 있다.


정리

  • 즉시실행 구문을 사용하면 javascript 가 유효범위를 선언 할 수 없다고 해도 강제적으로 private 변수를 만들어 내는 것이 가능 하다.

// i 라는 변수는 실행 시점에서만 사용되면 외부에서 접근 할수 없다. 
(function() {
   var i  = 'hello world' ;
}());

console.log(i)
> error

즉 익명함수는 동적으로 할당되는 유효범위를 가지기 때문에 javascript 내에서 강제적인 유효범위 설정을 하는 경우 사용되게 됩니다.

함수 선언식과 함수 표현식에 따른 차이 (함수 표현식 방법을 권장) 


이유 ? 

함수 표현식은 함수 선언식과 달리 스크립트 로딩 시점에 변수 객체(VO)에 함수를 할당하지 않고 runtime에 실행됨 -> 너무 많은 코드를 변수 객체(VO)에 저장하면 어플리케이션의 응답속도가 떨어짐


Javascript 모듈 패턴


javascript 의 모듈 패턴은 javascript 의 코드 관리 기법 중하나로서 javascript의 특성상 객체 핸들링을 위한 방법론중 하나이다.

javascript 의 모듈 패턴은 일반적인 유효범위를 설정하는 언어에서와 같이 private 와 public 등의 캡슐화를 사용하는 방법이다.

javascript 에서 함수 혹은 변수객체를 다룰때 중복된 name 사용으로 인한 문제를 방지하기 위해 주로 namespace 방법이 사용된다. 이는 global 영역에 객체 고유의 영역을 지정하고 변수와 함수 할당을 해당 namespace 하위로 두게 하여 중복된 name 으로 인한 오류를 피하는 방법이다.

모듈 패턴은 이 네임스페이스 페턴에 언어적 유효범위를 추가 해논 것이라 이해하면 쉽다.

모듈을 작성함에 있어서 return 구문을 이용하여 공개될 영역과 내부적으로 처리할 영역을 구분하여 공개여부를 선택하게 하는 것이다.



// namespace 패턴
var myApp = myApp || {}; // 네임 스페이스 선언

myApp.hanq= function() {
    return 'hanq';
};

myApp.helloworld = function() {
    return 'hello world';
}

// 모듈 페턴


var Messages = {h : 'hello', w : 'world', insane:'insanehanq'};

var myApp = (function(msg) {
  var helloworld = msg.h+'  '+msg.w;
  var helloinsanehanq = msg.h+' '+msg.insane;

  var printInsane = function () {
     return helloinsanehanq;
  };

  var printhello = function() {
    return helloworld;
  };  

  return {
    foo1 : printInsane,
    foo2 : printhello
  };

})(Messages);


console.log(myApp.foo1());
> hello insanehanq
console.log(myApp.helloworld);
> undefined




참고한 사이트


'Javascript' 카테고리의 다른 글

Javascript .attr()과 .prop()의 차이점  (0) 2018.01.19
Javascript Scope (유효범위)  (0) 2018.01.19
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
링크
«   2024/03   »
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
31
글 보관함