5.1 네임스페이스 패턴

네임스페이스 패턴

네임스페이스는 프로그램에서 필요로 하는 전역 변수의 개수를 줄이는 동시에 과도한 접두어를 사용하지 않고도 이름이 겹치지 않게 해준다. 이러한 네임스페이스 패턴은 자바스크립트 언어에 내장된 기능은 아니지만 어렵지 않게 구현할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 전역 객체
var myApp = {};

// 생성자
myApp.parent = function() {};
myApp.child = function() {};

// 변수
myApp.some_var = 1;

// 객체 컨테이너
myApp.modules = {};

// 객체들을 컨테이너 안에 추가한다.
myApp.modules.module1 = {};
myApp.modules.module1.data = {a : 1, b : 2};
myApp.modules.module2 = {};

먼저 애플리케이션 전역 전용 객체 (위에선 myApp이 전역 전용 객체)를 생성한다. 그런 다음 모든 함수와 변수들을 이 전역 객체의 프로퍼티로 생성한다.

이 패턴은 코드에 네임스페이스를 지정해주며, 코드 내의 이름 충돌 뿐 아니라 이 코드와 같은 페이지에 존재하는 자바스크립트 라이브러리나 위젯 등 서드 파티 코드와의 이름 충돌도 방지해준다.

단점

  • 모든 변수와 함수에 접두어를 붙여야 하기 때문에 전체적으로 코드량이 약간 더 많아지고 따라서 다운로드해야 하는 파일 크기도 늘어난다.
  • 전역 인스턴스가 단 하나뿐이기 때문에 코드의 어느 한 부분이 수정되어도 전역 인스턴스를 수정하게 된다. 즉 나머지 기능들도 갱신된 상태를 물려받는다.
  • 이름이 중첩되고 길어지므로 프로퍼티를 판별하기 위한 검색 작업도 길고 느려진다. 이 장의 뒷부분에서는 이 단점을 해결하기 위한 방법으로는 샌드박스 패턴이 있다.

범용 네임스페이스 함수

프로그램의 복잡도가 증가하고 코드의 각 부분들이 별개의 파일로 분리되어 선택적으로 문서에 포함되게 되면, 어떤 코드가 특정 네임스페이스나 그 내부의 프로퍼티를 처음으로 정의한다고 가정하기가 위험하다. 그러므로 네임스페이스를 생성하거나 프로퍼티를 추가하기 전에 먼저 이미 존재하는지 여부를 확인하는 것이 최선이다.

1
2
3
4
5
6
// 생성 이전에 존재여부 확인
if( typeof myApp === "undefined"){
var myApp = {};
}
// 간략히 줄임
var myApp = myApp || {};

이런 확인작업의 추가는 상당량의 중복 코드를 발생시키므로 네임스페이스를 생성하는 재사용 가능한 함수를 만들어 두는편이 편하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var myApp = myApp || {};

myApp.namespace = function(ns_string){
var parts = ns_string.split('.'),
var parent = myApp,
var i;

if (parts[0] === "myApp"){
parts = parts.slice(1);
}

for(i=0; i<parts.length; i+=1){
if(typeof parent[parts[i]] === "undefined"){
parent[parts[i]] = {};
}
parent = parent[parts[i]];
}
return parent;
};

이 코드는 다음 모든 예에서 사용할 수 있다.

1
2
3
4
5
6
7
8
9
// 반환 값을 지역변수에 할당한다.
var module2 = myApp.namespace('myApp.modules.module2');
module2 === myApp.modules.module2; // true

// 첫 부분의 'myApp'을 생략하고도 쓸 수 있다.
myApp.namespace('modules.module51');

// 아주 긴 네임스페이스
myApp.namespace('once.upon.a.time.there.was.this.long.nested.property');

5.2 의존 관계 선언

자바스크립트 라이브러리들은 대개 네임스페이스를 지정하여 모듈화되어 있기 때문에, 필요한 모듈만 골라서 쓸 수 있다. 예를 들어 YUI2에는 네임스페이스 역할을 하는 YAHOO 라는 전역변수가 있다.

이때 함수나 모듈 내 최상단에, 의존 관계에 있는 모듈을 선언하는 것이 좋다. 즉 지역변수를 만들어 원하는 모듈을 가리키도록 선언하는 것이다.

1
2
3
4
5
6
7
var myFunction = function() {
// 의존관계에 있는 모듈들
var event = YAHOO.util.Event,
var dom = YAHOO.util.Dom;

// 이제 event와 dom 이라는 변수를 사용한다....
}

대단히 간단한 패턴이지만 상당히 많은 장점을 가지고 있다.

  • 의존 관계가 명시적으로 선언되어 있기 때문에 코드를 사용하는 사람이 페이지내에 반드시 포함시켜야 하는 스크립트 파일이 무엇인지 알 수 있다.
  • 함수의 첫머리에 의존 관계가 선언되기 때문에 의존 관계를 찾아내고 이해하기가 쉽다.
  • dom과 같은 지역 변수는 YAHOO와 같은 전역 변수보다 언제나 더 빠르며 YAHOO.util.Dom 처럼 전역 변수의 중첩 프로퍼티와 비교하면 더 말할 것도 없다. 의존 관계 선언 패턴을 잘 지키면 함수 안에서 전역 객체 판별을 단 한번만 수행하고, 이 다음부터는 지역 변수를 사용하기 때문에 훨씬 빠르다.
  • YUI 컴프레서나 구글 클로저 등 고급 압축 도구는 지역 변수명에 대해서는 event를 A 라는 글자 하나로 바꾸는 식으로 축약해 코드를 줄여준다. 하지만 전역 변수명 변경은 위험하기 때문에 축약하지 않는다.