본문으로 바로가기

네임스페이스 패턴


자바스크립트 코드의 재사용과 생산성을 향상시키고자 많은 라이브러리가 나오고 있다. 이러한 라이브러리를 제작할 때 일반적으로 가장 중요한 것은 다른 모듈로부터 독립성을 보장하고 상호 간섭하지 않게끔 네임스페이스(namespace) 를 사용하는 것이다. 

라이브러리를 사용하다 보면 언제든지 한쪽에서 사용한 타입명이 다른 쪽에서도 사용될 수도 있는데, 어디서 사용될 지 모르는 라이브러리를 만드는 경우라면 반드시 네임스페이스를 정의해 객체를 안전하게 분리/관리하는 것을 필수입니다.




네임스페이스는 프로그램에서 필요로 하는 전역 변수의 개수를 줄이는 동시에 과도한 접두어를 사용하지 않고도 이름이 겹치지 않게 해준다. 

수많은 함수, 객체, 변수들로 전역 유효범위를 어지럽히지 않는 대신, 애플리케이션이나 라이브러리를 위한 전역 객체를 하나 만들고 (단 하나만 만드는 것이 이상적이다.) 모든 기능을 이 객체에 추가하면 됩니다.


// 안티 패턴 : 전역 변수 5

// 생성자 함수 2
function Parent(){}
function Child(){}

// 변수 1
var some_var = 1;

// 객체 2
var module1 = {};
module1.data = {a: 1, b: 2};
var module2 = {};


위 코드를 살펴보면 전역 변수가 5개가 있는 것을 확인할 수 있다. 

이러한 코드는 전역 스코프를 어지럽히기 때문에 바람직하지 않은 안티 패턴이다. 


위와 같은 코드를 리팩터링하기 위해서는 먼저 애플리케이션 전용 전역 객체, 이를 테면 MYAPP을 생성한다.  

그런 다음 모든 함수와 변수들을 이 전역 객체의 프로퍼티로 변경한다.


// 리팩토링 후 : 전역변수는 1개만 존재

// 전역 객체
var MYAPP = {};

// 생성자
MYAPP.Parent = function(){};
MYAPP.Child = function(){};

// 변수
MYAPP.some_var = 1;

// 객체 컨테이너
MYAPP.module = {};

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


위 코드와 같이 전역 스코프에는 하나의 전역변수만 둔다.

전역 네임스페이스 객체의 이름은 애플리케이션 이름이나 라이브러리의 이름, 도메인명, 회사 이름중에서 선택할 수 있다.





범용 네임스페이스 함수

프로그램의 복잡도가 증가하고 코드의 각 부분들이 별개의 파일로 분리되어 선택적으로 문서에 포함되게 되면, 어떤 코드가 특정 네임스페이스나 그 내부의 프로퍼티를 처음으로 정의한다고 가정하기가 위험하다. 네임스페이스에 추가하려는 프로퍼티가 이미 존재할 수도 있고 따라서내용을 덮어쓰게 될지도 모른다. 


그러므로 네임스페이스를 생성하거나 프로퍼티를 추가하기 전에 먼저 이미 존재하는지 여부를 확인하는 것이 최선이다.


// 안티 패턴
var MYAPP = {};

// 개선된 패턴
if(typeof MYAPP === "undefined"){
var MYAPP = {};
}

//또는 더 짧게 쓸 수 있다.
var MYAPP = MYAPP || {};


이렇게 네임스페이스와 네임스페이스의 프로퍼티가 존재여부를 확인하는 작업으로 인해 많은 양의 중복 코드가 생겨 날 수가 있디. 

따라서 네임스페이스 생성의 실제 작업을 맡아 줄 재사용 가능한 함수를 만들어 두면 코드의 재사용성이 높아진다.


// 네임스페이스 함수를 사용하여 네임스페이스와 네임스페이스의 프로퍼티를 확인한다
MYAPP.namespace('MYAPP.modules.module2');

// namespace함수를 사용하면 다음과 같은 결과를 반환한다.
var MYAPP = {
modules : {
module2: {}
}
};


다음은 네임스페이스 함수를 구현한 예제다. 

다음과 같은 방식은 네임스페이스가 존재하면 덮어쓰지 않기 때문에 기존 코드를 망가뜨리지 않는다.

var MYAPP = MYAPP || {};

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

//처음에 중복되는 전역 객체명은 제거한다.
if(parts[0] === 'MYAPP'){
parts = parts.slice(1);
}

for(i=0; i<parts.length; i++){
//프로퍼티가 존재하지 않으면 생성한다.
if(typeof parent[parts[i]] === 'undefined'){
parent[parts[i]] = {};
}
parent = parent[parts[i]];
}
return parent;
};



이 코드는 다음과 같이 사용할 수 있다.


// 반환 값을 지역변수에 할당한다.
var module2 = MYAPP.namespace('MYAPP.modules.module2');
module2 ==== MYAPP.modules.module2; // true

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




Jaehee's WebClub