본문 바로가기
웹 프로그래밍

[JavaScript] - 네임스페이스 (Namespace)

by CHML 2016. 9. 11.
1. 네임스페이스

네임스페이스는 이름이 존재하는 공간과 같다. 우리는 이름이 C로 같은 두 사람을 구분할 때, A 지역에 거주하는 C와 B 지역에 거주하는 C로 구분하기도 한다. 이러한 구분에서 이름이 C로 같은 두 사람이 A와 B라는 서로 다른 지역 (공간)에 존재했기 때문에 우리는 두 사람을 식별할 수 있었다.

복잡한 프로그램을 개발하거나, 협업을 하다보면 전역 범위에 위의 예시와 같이 이름이 같은 변수, 함수, 객체 등을 정의하는 경우가 발생한다. 네임스페이스는 이러한 경우에 발생할 수 있는 충돌을 방지하기 위해 이름이 존재하는 공간을 정의하는 기능을 제공한다.

네임스페이스 기능을 제공하는 대표적인 언어로는 C++와 자바가 있다. C++에서는 아예 namespace라는 키워드를 이용하여 변수, 함수, 객체의 네임스페이스를 지정할 수 있다 [코드 1]. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
 
namespace A {
    void add() {
        std::cout << "call add() from A" << std::endl;
    }
}
 
namespace B {
    void add() {
        std::cout << "call add() from B" << std::endl;
    }
}
 
int main()
{
    A::add();
    B::add();
 
    return 0;
}
cs

[코드 1] C++의 네임스페이스


자바에서는 패키지 (package)라는 개념을 이용하여 네임스페이스 기능을 제공한다. 다음의 [코드 2, 3]과 같이 이름이 각각 module1, module2라는 패키지에 MyClass라는 동일한 이름의 클래스가 정의되어 있다. 



1
2
3
4
5
6
7
package module1;
 
public class MyClass {
    public MyClass() {
        System.out.println("I'm from module1");
    }
}
cs

[코드 2] module1 패키지의 MyClass


1
2
3
4
5
6
7
package module2;
 
public class MyClass {
    public MyClass() {
        System.out.println("I'm from module2");
    }
}
cs

[코드 3] module2 패키지의 MyClass


[코드 2, 3]과 같이 정의된 MyClass가 있을 때, main 함수에서 MyClass를 이용하기 위해 [코드 4]를 작성하였다.


1
2
3
4
5
6
7
8
9
10
package exec;
 
import module1.*;
import module2.*;
 
public class Main {
    public static void main(String[] args) {    
        MyClass mc = new MyClass();
    }
}
cs

[코드 4] MyClass를 이용하기 위한 main 함수의 내용


자바에서는 [코드 4]와 같이 코드를 작성하면, MyClass를 선언하는 부분에서 어떠한 패키지의 MyClass를 의미하는지가 모호하기 때문에 컴파일 에러가 발생한다. 이러한 모호성을 제거하기 위해서는 import module1.MyClass처럼 명시적으로 어떠한 패키지의 MyClass를 포함할 것인지를 선언해야 한다.


2. 자바스크립트와 네임스페이스

자바스크립트는 C++나 자바처럼 네임스페이스 기능을 위한 별도의 키워드나 개념을 제공하지 않는다. 그러나 자바스크립트의 몇 가지 디자인 패턴을 이용하면, 네임스페이스와 동일한 기능을 수행하는 코드를 만들 수 있다. 아래의 [코드 5]는 자바스크립트의 객체 개념을 이용하여 네임스페이스의 개념을 구현한 것이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var MyModule = {};
var value = 1;
 
function callSender() {
    console.log('call sender');
}
 
MyModule.value = 5;
MyModule.callSender = function () {
    console.log('I am a sender.');
}
 
window.onload = function () {
    console.log(value);
    console.log(MyModule.value);
    callSender();
    MyModule.callSender();
}
cs

[코드 5] 네임스페이스 MyModule 정의 1


[코드 5]의 실행 결과는 아래의 [그림 1]과 같다. [코드 5]의 2번째 줄에서는 전역적으로 참조가 가능한 value라는 변수를 선언하고, 1이라는 값을 할당하였다. 그 다음, 8번째 줄에서는 MyModule이라는 네임스페이스를 갖는 value라는 변수를 선언하고, 5라는 값을 할당하였다. 4번째 줄과 9번째 줄의 callSender()라는 함수 또한 하나는 전역 참조가 가능하도록, 나머지 하나는 MyModule이라는 네임스페이스를 갖도록 선언하였다.


[그림 1] MyModule 네임스페이스 코드에 대한 실행 결과


자바스크립트에서는 네임스페이스를 구현하기 위해 여러 디자인 패턴을 사용할 수 있다. 아래의 [코드 6]은 [코드 5]에서 네임스페이스 MyModule을 정의하는 코드와 동일하다.


1
2
3
4
5
6
var MyModule = {
    value1: 5,
    callSender: function () {
        console.log('I am a sender');
    }
}
cs

[코드 6] 네임스페이스 MyModule 정의 2


그러나 [코드 5, 6]과 같이 객체의 개념을 이용하여 구현하는 네임스페이스는 객체의 이름이 충돌하는 것과 같이 네임스페이스의 이름 또한 충돌할 수 있다. 이러한 네임스페이스 간의 충돌을 방지하기 위해 [코드 7]과 같이 네임스페이스를 정의할 수 있다. [코드 7]에서는 네임스페이스를 정의하기 전에 기존에 동일한 이름을 갖는 네임스페이스가 존재하는지를 검사하고, 동일한 이름을 갖는 네임스페이스가 없을 경우에만 네임스페이스를 정의한다.


1
2
3
if (typeof MyModule === 'undefined') {
    var MyModule = {};
}
cs

[코드 7] 네임스페이스 간의 충돌 검사 1


위의 [코드 7]을 간소화하면, 아래의 [코드 8]과 같이 작성할 수 있다.


1
var MyModule = MyModule || {};
cs

[코드 8] 네임스페이스 간의 충돌 검사 2