네임스페이스란 수많은 함수, 객체, 변수들로 이루어진 코드가 전역 유효범위를 어지럽히지 않고, 애플리케이션이나 라이브러리를 위한 하나의 전역 객체를 만들고 모든 기능을 이 객체에 추가하는 것을 말한다.
즉, 코드에 네임스페이스를 지정해주면, 코드 내의 이름 충돌뿐만 아니라 이 코드와 같은 페이지에 존재하는 또 다른 자바스크립트 라이브러리나 위젯 등 서드파티 코드와의 이름 충돌도 미연에 방지할 수 있다.
이러한 네임스페이스를 자바스크립트에서는 모듈패턴으로 흉내낼 수 있다.
모듈이란 전체 애플리케이션 중 일부를 독립된 코드로 분리해서 만들어 놓은 것이다. 유용한 기능을 모아둔 것으로 볼 수 있다.
자바스크립트에서는 모듈을 구현하는 가장 쉬운 방법은 객체 리터럴을 사용하는 방법이다.
var module = {
key : 'value',
pulicMethod : function () { }
}
즉, 객체 리터럴은 하나의 객체라는 점에서 싱글톤 패턴으로 볼 수도 있고, 독립된 모듈이라는 점에서 모듈패턴으로 볼 수도 있다.
독립된 모듈은 자체적으로 필요한 내부 변수 및 내부 함수를 모두 갖고 있어야 하므로 클로저를 이용하여 구현해야 한다.
var Module = (function () {
// 은닉될 멤버
var privateKey = 0;
function privateMethod() {
return ++privateKey;
}
// 공개될 멤버 (특권 메소드) 정의
return {
publickey : privateKey,
publicMethod : function () {
return privateMethod();
}
}
})();
console.log(Module.publicMethod()); // 1
console.log(Module.publicMethod()); // 2 (클로저로 인한 결과)
위의 코드를 실행하면 익명함수가 자동으로 호출되어 익명함수가 반환하는 객체가 Module 변수에 할당된다.
아래와 같이 자동으로 호출(self-invoking)되는 구조를 없애면, 여러 개의 인스턴스를 생성할 수 있다.
var Module = function () {
// 은닉될 멤버 정의
var privateKey = 0;
function privateMethod() {
return ++privateKey;
}
// 공개될 멤버 (특권 메소드) 정의
return {
publickey : privateKey,
publicMethod : function () {
return privateMethod();
}
}
};
var obj1 = Module();
obj1.publicMethod(); // 1 출력
obj1.publicMethod(); // 2 출력
var obj2 = Module();
obj2.publicMethod(); // 1 출력
obj2.publicMethod(); // 2 출력
내부의 익명함수에서 함수가 아니라 객체를 반환한다는 점에서 클로저와 차이점이 있다.
단점
장점
// 1. 네임스페이스를 설정하고 모듈을 정의
var MyApp = {} // 전역 객체
MyApp.modules = {}
/*
2. 공개범위(특권메소드 등..)와 비공개 유효범위를 만든다
-> 즉시 실행함수로 모듈이 될 객체를 반환하고, 공개 인터페이스가 담기게 된다.
*/
MyApp.modules.libs = (function() {
// 비공개 프로퍼티 (private 멤버)
// 공개 프로퍼티 (public, previlege 멤버)
return {
};
}());
자바스크립트의 경우, private, protected, public
속성을 나타내는 별도의 문법이 없다.
자바스크립트 객체의 프로퍼티는 모두 public하다.
하지만 private member
의 개념이 존재하긴 하는데,
예를 들어 함수 안에서 정의한 변수는 함수 밖에서 접근할 수 없으므로 private member
로 여겨진다. (함수의 매개변수, 지역 변수, 내부 함수 등)
프로그램의 복잡도가 증가하고 코드의 각 부분들이 별개의 파일로 분리되어 선택적으로 문서에 포함하게 되면, 어떤 코드가 특정 네임스페이스나 그 내부의 프로퍼티를 처음으로 정의한다고 가정하는 것은 위험하다. 네임스페이스에 추가하려는 프로퍼티가 이미 존재한다면 내용을 덮어쓰게 될 수도 있다.
따라서 네임스페이스를 생성하거나 프로퍼티를 추가하기 전에 존재 여부를 확인해야 한다.
// 위험
var MYAPP = {};
// 개선안 1
if (typeof MYAPP === 'undefined') {
MYAPP = {};
}
// 개선안 2
var MYAPP = MYAPP || {};
이렇게 추가되는 확인 작업 때문에 상당량의 중복 코드가 생겨날 수 있다.
따라서 네임스페이스 생성의 실제 작업을 맡아 줄 재사용 가능한 함수를 만들어두면 편리하다.
다음은 네임스페이스 함수를 구현한 예제이다.
해당 네임스페이스가 존재하면 덮어쓰지 않기 때문에 기존 코드를 망가뜨리지 않는다.
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 += 1) {
if (typeof parent[parts[i]] === 'undefined') {
parent[parts[i]] = {};
}
parent = parent[parts[i]];
}
return parent;
};
자바스크립트 라이브러리들은 대개 네임스페이스를 지정하여 모듈화되어 있기 때문에, 필요한 모듈만 골라서 사용할 수 있다. 이때 함수나 모듈 최상단에, 의존 관계에 있는 모듈을 선언하는 것이 좋다.
즉, 지역변수를 만들어 모듈을 가리키도록 선언하는 것이다.
var myFunction = function () {
// 의존 관계에 있는 모듈들
var event = YAHOO.util.Event,
dom = YAHOO.util.Dom;
// event 와 dom 변수 사용 가능
};
간단하지만 상당히 많은 장점을 가진다.