본문 바로가기

FRONT-END/JAVASCRIPT

자바스크립트 디자인 패턴 #1. Module 패턴

반응형

모듈패턴

서버개발을 하거나 라이브러리,  API등을 개발할 때 유용하게 사용할 수 있다.

파일 단위로 관리할 수 있도록 자바스크립트를 모듈화해주고, 단위테스트를 모듈 단위로 실행할 수 있도록 하여 시험 계획에도 도움이 된다.

글로벌 변수나 함수들을 최소화함으로써 다른 자바스크립트 라이브러리나 소스를 가져다 쓸 때 충돌이 일어날 확률을 최소화한다.

또 모듈단위로 소스를 갭라하면 각 모듈 간의 의존성을 최소화하거나 의존성을 파악하기 쉽다.

장기적이고 규모가 큰 자바스크립트 프로젝트를 관리하기가 좋다.

자바스크립트 라이브러리나 API 등을 개발하여 다른 개발자들에게 제공할 때, 이를 활용하는 개발자들이 모듈단위로 함수나 변수들의 활용도를 예측할 수 있는 네임스페이스로도 활용 할수 있다.


(function(window) {

var myLibrary = {

helloWorld: function(){

alert("Hello World!");

},

hello: {

world: function(){

alert("Hello Module!!");

}

}

};


window.myLibrary = myLibrary;

}(window))


myLibrary.helloWorld();

myLibrary.hello.world();

즉시 호출 함수 안에서 myLibrary라는 변수를 선언하고, 해당 변수를 글로벌 영역에 노출한다.

이렇게 하면 외부에서 이 함수를 사용하려고 할 때 내부함수들을 활용할 수 있다.


직접 글로벌 영역에 변수를 선언하여 모듈 내부에 생성한 변수를 즉시 호출 함수의 반환값으로 선언하는 방법

var myLibrary = (function (window){

var myLibrary = {

helloWorld: function(){

alert("Hello World!");

}

};

return myLibrary;

}(window));

myLibrary.helloWorld();


내부에 변수를 선언하지 않고 바로 객체 표현식으로 반환하는 방법

var myLibrary = (function (window){

return {

helloWorld: function(){

alert("Hello World!");

}

};

}(window));

myLibrary.helloWorld();


다양하게 모듈을 생성하고 응용할 수 있다.

모듈의 형태를 확장하여 다양한 자바스크립트 라이브러리들에서는 네임스페이스로 활용하고 있다.




구글 API

var latlng = new google.maps.LatLng(-34.397, 150.644);

var map = new google.maps.Map(document.getElementById("canvas"), {

center: latlng

});

구글맵에서는 모든 생성자 앞에"google.maps"라는 접두어가 붙는다.

복잡한 자바스크립트 라이브러리에서 특정회사나 라이브러리의 용도를 명확하게 구분하고자 모듈 패턴을 확장하여 네임스페이스로 화룡하는 것이 일반적이다.


현재의 함수가 어떤 API인지, 그리고 어떤 용도인지 구분하는 용도로 네임스페이스를 활용하면 좋다.


(function(windows, undefined){

var _myLibrary = window.myLibrary;

if(!_myLibrary){

_myLibrary = {};

}

if(!_myLibrary.unikys){

_myLibrary.unikys = {};

}

_myLibrary.unikys.sayHello = function (){

alert("Hello, my name is Unikys");


};

window.myLibrary = _myLibrary;

}(window));


myLibrary.unikys.sayHello();

_myLibrary 변수에 글로벌 영역에 선언하고자 하는 네임스페이스를 가져오려고 한다.

다른 모듈에서 myLibrary 네임스페이스를 이미 정의했다면 해당 모듈은 그대로 사용하여 새로운 네임스페이스를 확장하듯이 설정한다.

이어서 myLibrary 안에 다시 unikys라는 네임스페이스가 정의되어있는지 확인한 다음 정의되어있지 않다면 새로운 객체를 생성하여 할당하고,

생성되어 있다면 해당 네임스페이스를 그대로 활용하여 확장한다.

그리고 해당 네임스페이스에 자유롭게 함수나 변수들을 활당하여 네임스페이스 구조를 완성하면된다.

마지막으로 처음 받았던 네임스페이스에 대한 변수를 다시 글로벌 영역에 설정함으로써 현재 소스에서 추가하려고 했던 네임스페이스를 다시 배포하는 역할을 수행한다.

결과적으로  myLibrary의 모듈이 기존에 이미 있었다면, 해당 모듈에 원하는 기능만 추가하는 것이다.


이처럼 자바스크립트는 다른 객체에 대하여 자유롭게 확장하고 다시 할당할 수 있다.

따라서 네임스페이스로 큰 단위 프로젝트를 수행할 때 기본적으로 이러한 방식의 방어적인 프로그래밍에 유용하다.



jQuery처럼 오픈 소스 라이브러리를 확장할 때도 이러한 방식으로 사용하는 것이 다른 라이브러리로 인한 영향을 최소화하는 방어적인 프로그래밍이다.

jQuery는 조금 더 복잡한 방법으로 모듈 패턴을 사용하고 아울러 확장까지 고려하여 다른 개발자들이 다양한 플러그인을 쉽게 추가할수 있도록 만들어졌다.


jQuery = function(selector. context){

return new jQuery.fn.init(selector, context);

},


jQuery.fn  = jQuery.prototype = {

//생략

}


init = jQuery.fn.init = function(selector, context){

//생략

};


init.prototype = jQuery.fn;

//생략

jQuery라는 변수는 함수로 정의되어, jQuery.fn.init 생성자의 인스턴스를 새로 생성하여 반환한다.

이 생성자는 init라는 변수에 다시 정의되고, init 생성자의 프로토타입은 jQuery.fn으로 설정된다.

따라서 jQuery 함수의 결과로 나오는 모든 변수를 jQuery.fn이 프로토타입으로 설정되는 것이다.

jQuery에서는 이 jQuery 변수를 글로벌 영역에 도 노출하고, 똑같은 변수인 $에도 할당하므로 $("selector") 처럼 호출하는 모든 함수는 jQuery.fn의 속성으로 있는 변수와 함수들을 사용할 수 있다.

따라서 jQuery를 확장하는 플러그인을 개발할 때 jQeury.fn에 추가 속성을 설정하면 모든 $()로 선택되는 jQeury 객체들을 사용할 수 있다.


정리)

모듈패턴은 객체를 자유롭게 확장하고 자바스크립트의 특성을 잘 살리면서 잠재적인 프로그래밍 위험요소를 최소화한다.

모듈패턴은 다른 여러 라이브러리와 조합하여 사용하거나 여러 개발자가 동시에 개발해야하는 복잡한 프로젝트에 채택하면 좋다.


출처-속깊은 자바스크립트 양성익 지음

반응형