스태틱 멤버



// 생성자
var Gadget = (function(){

// 스태틱 변수/프로퍼티
var counter = 0,
NewGadget;
// 이 부분이 생성자를 새롭게 구현한 부분
NewGadget = function(){
console.log(counter += 1);
};

// 특권 메서드
NewGadget.prototype.getLastId = function(){
return counter;
};

// 생성자를 덮어쓴다.
return NewGadget;
}());

var iphone = new Gadget();
iphone.getLastId(); // 1
var ipod = new Gadget();
ipod.getLastId(); // 2
var ipad = new Gadget();
ipad.getLastId(); // 3


전역 생성자


네임스페이스 패턴에서는 전역 객체가 하나다. 샌드박스 패턴의 유일한 전역은 생성자다.
// 샌드박스 사용법은 다음과 같다.
new Sandbox(function (box){
// 여기에 코드가 들어감
});

다음과 같이 new를 쓰지 않고도 가상의 모듈 'ajax'와 'event'를 사용하는 객체를 만들 수 있다.
Sandbox(['ajax', 'event'], function(box){
//console.log(box);
})

// 개별적인 인자로 전달 할 수 있다
Sandbox('ajax','dom', function(box){
//console.log(box);
})

샌드박스 객체의 인스턴스를 여러 개 만드는 예제
Sandbox(['dom', 'events'], function(box) {
// box 객체는 dom, events 모듈이 결합되어 있다.

Sandbox('ajax', function(box) {
// box 객체는 ajax 모듈만 결합되어 있다.
// 이 box 객체는 바깥 쪽 box 객체와 다르다.
});
});




모듈 추가하기


실제 생성자를 구현하기 전에 모듈을 어떻게 추가할 수 있는지 확인
// Sandbox 모듈 객체
Sandbox.modules = {};

// Sandbox 모듈 dom 정의
Sandbox.modules.dom = function(box) {
box.query = function(selector, context) {};
box.queryAll = function(selector, context) {};
box.css = function(el, prop, value) {};
}

// Sandbox 모듈 events 정의
Sandbox.modules.events = function(box) {
// 필요에 따라 Sandbox 프로토타입 객체에 접근 가능
// box.constructor.prototype.prop = 'value';
box.on = function(el, type, handler, capture) {};
box.off = function(el, type, handler, capture) {};
}

// Sandbox 모듈 ajax 정의
Sandbox.modules.ajax = function(box) {
box.makeRequest = function() {};
box.getResponse = function() {};
}




생성자 구현


function Sandbox() {
// arguments를 배열로 변경한다.
var args = Array.prototype.slice.call(arguments),
// 마지막 인자는 항상 콜백 함수이다.
callback = args.pop(),
// 모듈 이름은 배열 또는 문자열로 전달될 수 있다.
modules = (args[0] && typeof args[0] === 'string') ? args : args[0],
i;

// new를 강제화하는 패턴
if ( !(this instanceof Sandbox) ) {
return new Sandbox(modules, callback);
}

// 생성된 인스턴스 객체(this)에 속성을 추가 한다.
this.prop1 = 'property 1';
this.prop2 = 'property 2';

// this 객체에 모듈을 추가한다.
// 모듈이 없거나, '*' 와일드 카드라면 모든 모듈을 사용한다.
if (!modules || modules === '*' || modules[0] === '*') {
modules = [];
for ( var module in Sandbox.modules) {
if(Sandbox.modules.hasOwnProperty(module)){
modules.push(module);
}
}
}

// 필요한 모듈을 초기화 한다.
modules.forEach(function(module, index) {
Sandbox.modules[ module ](this);
});

// 콜백 함수를 실행한다.
callback(this);
}

// Sandbox 프로토타입 객체
Sandbox.prototype = {
name: 'Application',
version: '1.0.2',
getName: function(){
return this.name;
}
// ...
};


이 구현에서 핵심적인 사항은 다음과 같다.

  • this가 Sandbox 인스턴스인지 확인 후, 생성자 함수로 호출한다. (new를 강제화하는 패턴)
  • 생성자 내부에서 this에 속성을 추가한다. 생성자의 프로토타입 객체에도 속성을 추가할 수 있다.
  • 필요한 모듈은 배열 또는 개별 문자 유형의 인자로 전달할 수 있고, * 와일드카드를 사용하거나, 쓸 수 있는 모든 모듈을 사용하겠다는 의미로 인자를 생략할 수도 있다.
  • 필요한 모듈을 모두 파악한 다음에는 각 모듈을 초기화한다. 정리하면 각 모듈을 구현한 함수를 호출해서 객체를 생성한다.
  • 생성자의 마지막 인자는 콜백 함수이다. 이 콜백 함수는 맨 마지막에 호출되며, 새로 생성된 인스턴스가 인자로 전달된다. 이 콜백 함수가 실제로 사용자의 샌드박스이며 필요한 기능을 모두 갖춘 상태에서 box 객체를 전달받게 된다.


모듈 패턴


모듈 패턴은 늘어나는 코드를 구조화하고 정리하는데 도움이 되기 때문에 널리 쓰인다.
모듈 패턴은 다음 여러 패턴 여러개를 조합한 것이다.
  • 네임 스페이스 패턴
  • 즉시 실행 함수
  • 비공개 멤버와 특권 멤버
  • 의존 관계 선언


MYAPP.namespace('MYAPP.utilties.Array');


// 모듈 정의
MYAPP.utilities.array = (function(){
// 의존관계
var uobj = MYAPP.utilities.object,
ulan = MYAPP.utilities.lang,
// 비공개 프로퍼티
ayyay_string = "[object Array]",
ops = Object.prototype.toString;

// 비공개 메서드

// var 선언 종료

// 필요시 일회성 초기화 실행

// 공개 API
return {
inArray: function(needle, haystack){
for(var i = 0, max = haystack.langth; i < max; i += 1){
if(haystackp[i] === needle){
return true;
}
}
},

isArray: function(a){
return ops.call(a) === array_string;
}
// 더 필요한 메서드 추가
}
}())



모듈 노출 패턴


모든 메서드를 비공개 상태로 유지하고 최종적으로 공개 API를 갖출 대 공개할 메서드만 골라서 노출 하는 것이다.

MYAPP.namespace('MYAPP.utilities.Array');

// 모듈 정의
MYAPP.utilities.array = (function(){
// 비공개 프로퍼티
var ayyay_string = "[object Array]",
ops = Object.prototype.toString;

// 비공개 메서드
inArray = function(needle, haystack){
for(var i = 0, max = haystack.langth; i < max; i += 1){
if(haystackp[i] === needle){
return i;
}
}
return -1;
},
isArray = function(a){
return ops.call(a) === array_string;
};
// var 선언 종료

// 공개 API
return {
inArray: inArray,
indexOd: inArray
};
}());




생성자를 생성하는 모듈


앞선 예제는 MYAPP, utilities, array 라는 객체를 만들었다. 하지만 생성자 함수를 사용해 객체를 만드는게 더 편할때도 있다.

MYAPP.namespace('MYAPP.utilities.Array');

// 모듈 정의
MYAPP.utilities.Array = (function(){
// 의존관계
var uobj = MYAPP.utilities.object,
ulan = MYAPP.utilities.lang,

// 비공개 메서드
inArray = function(needle, haystack){
for(var i = 0, max = haystack.langth; i < max; i += 1){
if(haystackp[i] === needle){
return I;
}
}
return -1;
},
isArray = function(a){
return ops.call(a) === array_string;
},
Constr;
// var 선언 종료

// 공개 API 생성자
Constr = function(o){
this.elements = this.toArray(o);
};
// 공개 API 프로토타입
Constr.prototype = {
constructor: MYAPP.utilities.Array,
version: "2.0",
toArray: function(obj){
for(var i = 0, a = [], len = obj.length; i < len; i += 1){
ap[i] = obj[i];
}
return a;
}
}

// 생성자 함수를 반환한다
// 이 함수가 새로운 네임스페이스에 할당 될 것이다.
return Constr;
}());

// 이 생성자 함수는 다음과 같이 사용
var arr = new MYAPP.utilities.Array(obj);



모듈에 전역 변수 가져오기


변경 패턴으로는 모듈을 감싼 즉시 실행 함수에 인자를 전달하는 형태가 있다.

// 모듈 정의
MYAPP.utilities.module = (function(app, global){
// 전역 객체에 대한 참조와
// 전역 어플리케이션 네임스페이스 객채에 대한 참조가 지역 변수화 된다.
}(MYAPP, this));


+ Recent posts