JavaScript로 네임 스페이스를 어떻게 선언합니까?


990

JavaScript로 네임 스페이스를 작성하여 객체와 함수를 다른 이름의 객체와 함수로 덮어 쓰지 않도록하려면 어떻게해야합니까? 나는 다음을 사용했다 :

if (Foo == null || typeof(Foo) != "object") { var Foo = new Object();}

이것을하는 더 우아하거나 간결한 방법이 있습니까?


20
네임 스페이스가 사용되는지 확인하기 위해 검사를 진행하는 곳을 볼 수 있지만 이것이 실패하면 객체가 생성되지 않으므로 네임 스페이스가 사용되면 경고하는 것이 더 나은 방법이라고 생각합니다. 솔직히 이것은 대부분의 JS 상황에서 발생해서는 안되며 개발 과정에서 빠르게 포착되어야합니다.
annakata

18
최상위 "네임 스페이스"(창 속성)를 가져옵니다. 그것을 소유하십시오. 테스트 초기에 충돌이 감지되어야합니다. 이러한 "가정"검사를 모두 추가하지 않아도됩니다. 중복 된 "네임 스페이스"의 경우 치명적인 문제이므로 이와 같이 취급해야합니다 . jQuery와 같은 접근법을 따라 사용자 정의 "네임 스페이스"에 거주 할 수 있습니다. 그러나 이것은 여전히 디자인 타임 문제입니다.

훨씬 더 우아하고 업데이트 된 솔루션 인 stackoverflow.com/questions/881515/…로 허용되는 답변을 변경하십시오 .
hlfcoding

@pst YUI의 기능은 무엇입니까? 네임 스페이스에 점진적으로 추가하기 위해 정확히이 작업을 수행한다고 생각합니다. HTTP 환경에서의 성능을 위해서는 이와 같은 트릭이 필요합니까?
Simon_Weaver

성능 문제에 대해서는 stackoverflow.com/questions/2102591/… 도 참조하십시오
Tim Abell

답변:


764

나는 이것을 좋아한다 :

var yourNamespace = {

    foo: function() {
    },

    bar: function() {
    }
};

...

yourNamespace.foo();

62
중요한 점은 하나의 근본 변수 이상으로 확장하는 것에 대해 종교적이어야한다는 것입니다. 이것으로부터 모든 것이 흘러야합니다.
annakata

22
이렇게하면 코드가 닫히지 않습니다. 다른 함수는 항상 다음과 같이 보이기 때문에 다른 함수를 호출하는 것이 지루합니다. yourNamespace.bar (); :이 설계 문제를 해결하기 위해 그냥 오픈 소스 프로젝트 만든 github.com/mckoss/namespace을 .
mckoss

24
annakata : "중요한 요점은 하나의 근본 변수 이상으로 확장하는 것에 대해 종교적인 것입니다."-왜 그런가요?
user406905

11
@alex-왜 얕은 객체 구조가 있어야합니까?
Ryan

25
@Ryan 나는 모든 것이 아래에해야 의미 MyApp, 예를 들면 MyApp.Views.Profile = {}보다는 MyApp.users = {}하고 MyViews.Profile = {}. 반드시 2 단계의 깊이 만 있어야하는 것은 아닙니다.
alex

1042

Enterprise jQuery 사이트에서 찾은 접근 방식을 사용 합니다 .

다음은 개인 및 공용 속성 및 함수를 선언하는 방법을 보여주는 예입니다. 모든 것은 자체 실행 익명 기능으로 수행됩니다.

(function( skillet, $, undefined ) {
    //Private Property
    var isHot = true;

    //Public Property
    skillet.ingredient = "Bacon Strips";

    //Public Method
    skillet.fry = function() {
        var oliveOil;

        addItem( "\t\n Butter \n\t" );
        addItem( oliveOil );
        console.log( "Frying " + skillet.ingredient );
    };

    //Private Method
    function addItem( item ) {
        if ( item !== undefined ) {
            console.log( "Adding " + $.trim(item) );
        }
    }
}( window.skillet = window.skillet || {}, jQuery ));

따라서 공개 멤버 중 하나에 액세스하려면 skillet.fry()또는을 방문하십시오 skillet.ingredients.

정말 멋진 점은 이제 동일한 구문을 사용하여 네임 스페이스를 확장 할 수 있다는 것입니다.

//Adding new Functionality to the skillet
(function( skillet, $, undefined ) {
    //Private Property
    var amountOfGrease = "1 Cup";

    //Public Method
    skillet.toString = function() {
        console.log( skillet.quantity + " " +
                     skillet.ingredient + " & " +
                     amountOfGrease + " of Grease" );
        console.log( isHot ? "Hot" : "Cold" );
    };
}( window.skillet = window.skillet || {}, jQuery ));

세번째 undefined논쟁

세 번째 undefined인수는 value 변수의 소스입니다 undefined. 그것이 오늘날에도 여전히 관련이 있는지 확실하지 않지만 구형 브라우저 / JavaScript 표준 (ecmascript 5, javascript <1.8.5 ~ firefox 4)으로 작업하는 동안 전역 범위 변수 undefined를 쓸 수 있으므로 누구나 그 가치를 다시 쓸 수 있습니다. 세 번째 인수 (값을 전달하지 않은 경우) undefined는 네임 스페이스 / 함수로 범위가 지정된 변수를 만듭니다 . 네임 스페이스를 작성할 때 값이 전달되지 않았으므로 기본값은 value undefined입니다.


9
이 훌륭한 샘플에 +1. 사람이 관심을 경우,이 시료를 혼합 2,011 (제목을 무시)에서 엘리야 매너의 훌륭한 프리젠 테이션의 일부 live.visitmix.com/MIX11/Sessions/Speaker/Elijah-Manor
대런 루이스

11
엘리야의 기사에서이 방법의 장단점은 다음과 같습니다. 장점 : 1. 공개 및 개인 속성 및 방법, 2. 성가신 OLN을 사용하지 않음, 3. 정의되지 않은 보호 4. $가 jQuery를 참조하는지 확인합니다. 5. 네임 스페이스가 파일을 포함 할 수 있음, 단점 : OLN보다 이해하기 어려움
Jared Beck

4
이것을 오늘 IIFE ( 즉시 호출 함수 표현식 )라고합니다. 답변 +1 감사합니다!
Gustavo Gondim

20
@CpILL : 여전히 관련성이 있는지 확실하지 않지만 세 번째 undefined인수는 value 변수의 소스입니다 undefined. 구형 브라우저 / 자바 스크립트 표준 (ecmascript 5, javascript <1.8.5 ~ firefox 4)으로 작업하는 동안 전역 범위 변수 undefined를 쓸 수 있으므로 누구나 해당 값을 다시 쓸 수 있습니다. 세 번째로 전달하지 않는 추가 인수를 추가하면 value undefined가되므로 undefined외부 소스에서 다시 작성하지 않는 네임 스페이스 범위 를 작성했습니다.
mrówa

4
@SapphireSun 이점 window.skillet = window.skillet || {}은 실행 순서를 미리 모르는 경우 여러 스크립트가 동일한 네임 스페이스에 안전하게 추가 할 수 있다는 것입니다. 코드를 손상시키지 않고 스크립트 포함을 임의로 재정렬하려는 경우 또는 async 속성을 사용 하여 스크립트를 비동기식으로로드 하여 실행 순서를 보장하지 않는 경우 유용합니다 . 참조 stackoverflow.com/questions/6439579/...
마크 Amery

338

객체 리터럴 형식보다 조금 덜 제한적이라고 생각하는 또 다른 방법은 다음과 같습니다.

var ns = new function() {

    var internalFunction = function() {

    };

    this.publicFunction = function() {

    };
};

위의 내용은 모듈 패턴 과 비슷 하며 , 원하는지 여부에 관계없이 객체 리터럴의 엄격한 구조를 피하면서 모든 기능을 공개로 노출 할 수 있습니다.


16
1. OLN과 모듈 패턴에는 차이가 있습니다. 2. 마지막 쉼표를 넣지 말아야하고 모든 속성은 값 (예 : null 또는 undefined)으로 초기화해야한다는 것을 기억해야하기 때문에 OLN을 / always / 좋아하지 않습니다. 또한 멤버 함수에 대한 클로저가 필요한 경우 각 메소드마다 작은 함수 팩토리가 필요합니다. 또 다른 것은 모든 제어 구조를 함수 안에 포함시켜야하지만 위의 형식은 그것을 의미하지는 않습니다. 그것은 내가 OLN을 사용하지 않는다고 말하는 것이 아닙니다. 때로는 그것을 좋아하지 않습니다.
Ionuț G. Stan 9

8
개인 함수, 변수 및 의사 상수 (예 : var API_KEY = 12345;)를 허용하기 때문에이 방법이 마음에 듭니다.
Lawrence Barsanti

12
나는 투표율이 높은 쉼표로 구분 된 객체 컨테이너보다 이것을 좋아합니다. 비교할 때 단점도 보이지 않습니다. 뭔가 빠졌습니까?
Lucent

7
JS Newbie here ... 왜 내가 타이핑 할 필요가 없습니다 . ns().publicFunction()즉, ns.publicFunction()작동합니다.
존 크래프트

14
@John Kraft, new키워드 앞에 function키워드가 필요하기 때문입니다. 기본적으로 수행중인 작업은 익명 함수를 선언하고 (함수는 생성자이기도 함) 즉시를 사용하여 생성자로 호출한다는 것 new입니다. 따라서 내부 ns에 저장되는 최종 값 은 해당 익명 생성자의 (고유 한) 인스턴스입니다. 이해가 되길 바랍니다.
Ionuț G. Stan

157

이것을하는 더 우아하거나 간결한 방법이 있습니까?

예. 예를 들면 다음과 같습니다.

var your_namespace = your_namespace || {};

그럼 당신은 가질 수 있습니다

var your_namespace = your_namespace || {};
your_namespace.Foo = {toAlert:'test'};
your_namespace.Bar = function(arg) 
{
    alert(arg);
};
with(your_namespace)
{
   Bar(Foo.toAlert);
}

1
이것은 IE7에서 오류를 발생시킵니다. var your_namespace = (your_namespace의 유형 == "정의되지 않은"||! your_namespace)? {} : your_namespace; 더 잘 작동합니다.
mjallday

9
var your_namespace = your_namespace = your_namespace || 여야합니다. {} 모든 브라우저에서 작동;)
Palo

나에게서 +1! Thin은 하나의 라이브러리를 다른 파일 또는 동일한 파일 내의 다른 위치로 확장하여 Jaco Pretorius의 답변으로 작동합니다. 그냥 화려한!
센츄리

2
@Palo 왜 이런 식이어야하는지 설명해 주시겠습니까? var your_namespace = your_namespace = your_namespace || {}
스리랑

6
your_namespace 객체를 다른 js 파일로 확장 할 수 있습니다. var your_namespace = {}를 사용하면 각 파일이 객체를 덮어 쓰기 때문에 그렇게 할 수 없습니다.
Alex Pacurar

92

나는 일반적으로 클로저로 빌드합니다.

var MYNS = MYNS || {};

MYNS.subns = (function() {

    function privateMethod() {
        // Do private stuff, or build internal.
        return "Message";
    }

    return {
        someProperty: 'prop value',
        publicMethod: function() {
            return privateMethod() + " stuff";
        }
    };
})();

몇 년 동안 내 스타일은이 글을 쓴 후 미묘한 변화를 겪었으며 이제는 다음과 같이 클로저를 작성하는 것으로 나타났습니다.

var MYNS = MYNS || {};

MYNS.subns = (function() {
    var internalState = "Message";

    var privateMethod = function() {
        // Do private stuff, or build internal.
        return internalState;
    };
    var publicMethod = function() {
        return privateMethod() + " stuff";
    };

    return {
        someProperty: 'prop value',
        publicMethod: publicMethod
    };
})();

이런 식으로 공개 API와 구현을 이해하기가 더 쉽다는 것을 알게되었습니다. return 문은 구현에 대한 공용 인터페이스라고 생각하십시오.


3
확인하지 않겠습니까 MYNS.subns = MYNS.subns || {}??
Mirko

개발자의 의도에 대한 연습이되어야 할 좋은 점입니다. 존재하는 경우 수행 할 작업, 교체, 오류, 기존 또는 버전 확인 및 조건부 교체를 고려해야합니다. 각 변형을 요구하는 상황이 다릅니다. 대부분의 경우, 위험이 낮은 경우로 간주 할 수 있으며 교체가 유리할 수 있습니다. NS를 납치하려고 시도한 불량 모듈을 고려하십시오.
Brett Ryan

1
이 방법에 대한 설명은 "빠르고 더러운 모듈"이라는 제목 아래 412 페이지의 "Java 말하기"책에 설명되어 있습니다.
Soferio

2
최적화 팁 : 상태 var foo = functionfunction foo개인되고, 유사하다; JavaScript의 동적 형식 특성으로 인해 대부분의 인터프리터 파이프 라인에서 몇 가지 명령을 건너 뛰기 때문에 후자가 약간 더 빠릅니다. 를 사용 var foo하면 유형 시스템이 해당 var에 지정된 유형을 찾기 위해 호출되어야하지만 function foo유형 시스템은 자동으로 함수임을 알고 있으므로 몇 가지 함수 호출을 건너 뛰므로 CPU 명령 호출이 줄어 듭니다. jmp, pushq, popq, 등, 짧은 CPU 파이프 라인으로 변환한다.
Braden Best

1
@ 브렛 죄송합니다. 네가 옳아. 다른 스크립팅 언어를 생각하고있었습니다. 나는 여전히 function foo문법이 더 읽기 쉽다고 주장한다 . 그리고 나는 여전히 내 버전을 좋아합니다.
Braden Best

56

다른 JavaScript 파일을 작성하여 나중에 응용 프로그램에서 결합하거나 결합하지 않을 수 있으므로 각 파일은 다른 파일의 작업을 손상시키지 않으면 서 네임 스페이스 객체를 복구하거나 구성 할 수 있어야합니다.

하나의 파일이 네임 스페이스를 사용하려고 할 수 있습니다 namespace.namespace1.

namespace = window.namespace || {};
namespace.namespace1 = namespace.namespace1 || {};

namespace.namespace1.doSomeThing = function(){}

다른 파일은 네임 스페이스를 사용하려고 할 수 있습니다 namespace.namespace2.

namespace = window.namespace || {};
namespace.namespace2 = namespace.namespace2 || {};

namespace.namespace2.doSomeThing = function(){}

이 두 파일은 충돌하지 않고 함께 또는 떨어져있을 수 있습니다.


1
나는 이것이 기능성을 모듈화 해야하는 대규모 응용 프로그램에서 클라이언트 스크립트를 여러 파일로 구성하는 매우 유용한 방법이라는 것을 알았습니다.
DVK

질문은 여러 개의 파일을 위해 특별히 요청 : stackoverflow.com/questions/5150124/...
치로 틸리冠状病毒审查六四事件法轮功

48

다음은 Stoyan Stefanov가 JavaScript 패턴 책 에서 어떻게 수행했는지 잘 보여줍니다. (자동 생성 된 API 문서를 허용하는 주석과 사용자 정의 객체의 프로토 타입에 메소드를 추가하는 방법도 보여줍니다) :

/**
* My JavaScript application
*
* @module myapp
*/

/** @namespace Namespace for MYAPP classes and functions. */
var MYAPP = MYAPP || {};

/**
* A maths utility
* @namespace MYAPP
* @class math_stuff
*/
MYAPP.math_stuff = {

    /**
    * Sums two numbers
    *
    * @method sum
    * @param {Number} a First number
    * @param {Number} b Second number
    * @return {Number} Sum of the inputs
    */
    sum: function (a, b) {
        return a + b;
    },

    /**
    * Multiplies two numbers
    *
    * @method multi
    * @param {Number} a First number
    * @param {Number} b Second number
    * @return {Number} The inputs multiplied
    */
    multi: function (a, b) {
        return a * b;
    }
};

/**
* Constructs Person objects
* @class Person
* @constructor
* @namespace MYAPP
* @param {String} First name
* @param {String} Last name
*/
MYAPP.Person = function (first, last) {

    /**
    * First name of the Person
    * @property first_name
    * @type String
    */
    this.first_name = first;

    /**
    * Last name of the Person
    * @property last_name
    * @type String
    */
    this.last_name = last;
};

/**
* Return Person's full name
*
* @method getName
* @return {String} First name + last name
*/
MYAPP.Person.prototype.getName = function () {
    return this.first_name + ' ' + this.last_name;
};

32

나는이 접근법을 사용한다 :

var myNamespace = {}
myNamespace._construct = function()
{
    var staticVariable = "This is available to all functions created here"

    function MyClass()
    {
       // Depending on the class, we may build all the classes here
       this.publicMethod = function()
       {
          //Do stuff
       }
    }

    // Alternatively, we may use a prototype.
    MyClass.prototype.altPublicMethod = function()
    {
        //Do stuff
    }

    function privateStuff()
    {
    }

    function publicStuff()
    {
       // Code that may call other public and private functions
    }

    // List of things to place publically
    this.publicStuff = publicStuff
    this.MyClass = MyClass
}
myNamespace._construct()

// The following may or may not be in another file
myNamespace.subName = {}
myNamespace.subName._construct = function()
{
   // Build namespace
}
myNamespace.subName._construct()

외부 코드는 다음과 같습니다.

var myClass = new myNamespace.MyClass();
var myOtherClass = new myNamepace.subName.SomeOtherClass();
myNamespace.subName.publicOtherStuff(someParameter);

훌륭한 세부 사항! 감사! Namespace.js에 무엇이 필요한지 궁금합니다. 나는 그것을 직접 사용해 본 적이 없기 때문에 지식 / 기술 / 경험이있는 사람이 그것을 사용할 것인지 궁금합니다.
John

나는 그것을 좋아한다! 반면 에이 외부 코드의 첫 번째 줄에서 예외가 발생합니다. 'myNameSpace.MyClass'[정의되지 않음]은 생성자가 아닙니다. 아마도 JS 구현에 달려 있습니까? : /
yoosiba

@yossiba : 가능합니다. 위의 코드는 상당히 표준적인 것입니다. 표준 JS에서는 모든 함수를 생성자로 사용할 수 있습니다. 함수를 생성자로 사용하기 위해 특별히 표시하기 위해 수행해야 할 작업은 없습니다. ActionScript와 같은 특이한 맛을 사용하고 있습니까?
AnthonyWJones

@Anthony가 var MYNAMESPACE = MYNAMESPACE를 사용하는 것이 좋습니다. {}; var myNamespace = {}를 사용하는 것은 안전하지 않으며 또한 네임 스페이스를 대문자로 선언하는 것이 좋습니다.
paul

9
@paul : "더 나은"것은 아주 주관적 일 수 있습니다. 나는 나에게 소리 치는 코드를 싫어하므로 모든 대문자를 사용하는 식별자를 사용하지 마십시오. 반면 ns = ns || {}힘은 다른 예기치 않은 결과가 발생할 수 있습니다 더 방어 보인다.
AnthonyWJones

32

다음은 userspace826의 Namespace.js 링크에 대한 후속 조치입니다. 프로젝트가 GitHub 로 옮겨 간 것 같습니다 . 이제 smith / namespacedotjs 입니다.

나는 작은 프로젝트 에이 간단한 JavaScript 도우미를 사용해 왔으며 지금까지 네임 스페이스 로드 모듈 / 클래스 를 처리 할 수있을만큼 가볍고 다재다능 합니다. 전역 네임 스페이스뿐만 아니라 한숨을 내쉬고 선택한 네임 스페이스로 패키지를 가져올 수 있다면 좋을 것입니다. 그러나 그것은 요점입니다.

네임 스페이스를 선언 한 다음 해당 네임 스페이스에서 객체 / 모듈을 정의 할 수 있습니다.

Namespace('my.awesome.package');
my.awesome.package.WildClass = {};

또 다른 옵션은 네임 스페이스와 해당 내용을 한 번에 선언하는 것입니다.

Namespace('my.awesome.package', {
    SuperDuperClass: {
        saveTheDay: function() {
            alert('You are welcome.');
        }
    }
});

더 많은 사용법 예제 는 source 에서 example.js 파일을보십시오 .


2
my.awesome.package.WildClass에 액세스 할 때마다 my의 멋진 속성, my.awesome의 패키지 속성 및 my.awesome의 WildClass 속성에 액세스하게됩니다. 꾸러미.
SamStephens

29

견본:

var namespace = {};
namespace.module1 = (function(){

    var self = {};
    self.initialized = false;

    self.init = function(){
        setTimeout(self.onTimeout, 1000)
    };

    self.onTimeout = function(){
        alert('onTimeout')
        self.initialized = true;
    };

    self.init(); /* If it needs to auto-initialize, */
    /* You can also call 'namespace.module1.init();' from outside the module. */
    return self;
})()

당신은 선택적으로 선언 할 수 있습니다 local, 변수를 same같이 self하고 지정 local.onTimeout이 비공개로합니다.


14

네임 스페이스를 제공하는 간단한 함수를 선언 할 수 있습니다.

function namespace(namespace) {
    var object = this, tokens = namespace.split("."), token;

    while (tokens.length > 0) {
        token = tokens.shift();

        if (typeof object[token] === "undefined") {
            object[token] = {};
        }

        object = object[token];
    }

    return object;
}

// Usage example
namespace("foo.bar").baz = "I'm a value!";

13

개인 범위가 필요한 경우 :

var yourNamespace = (function() {

  //Private property
  var publicScope = {};

  //Private property
  var privateProperty = "aaa"; 

  //Public property
  publicScope.publicProperty = "bbb";

  //Public method
  publicScope.publicMethod = function() {
    this.privateMethod();
  };

  //Private method
  function privateMethod() {
    console.log(this.privateProperty);
  }

  //Return only the public parts
  return publicScope;
}());

yourNamespace.publicMethod();

개인 범위를 사용하지 않는 경우 :

var yourNamespace = {};

yourNamespace.publicMethod = function() {
    // Do something...
};

yourNamespace.publicMethod2 = function() {
    // Do something...
};

yourNamespace.publicMethod();

12

모듈 패턴은 원래 기존 소프트웨어 엔지니어링의 클래스에 개인 및 공개 캡슐화를 모두 제공하는 방법으로 정의되었습니다.

모듈 패턴으로 작업 할 때 시작하기 위해 사용하는 간단한 템플릿을 정의하는 것이 유용 할 수 있습니다. 이름 간격, 공용 및 개인 변수를 다루는 것이 있습니다.

JavaScript에서 모듈 패턴은 단일 객체 내에 공개 / 비공개 메소드와 변수를 모두 포함 할 수있는 방식으로 클래스 개념을 추가로 에뮬레이트하는 데 사용되므로 특정 부분을 전역 범위로부터 보호합니다. 결과적으로 함수 이름이 페이지의 추가 스크립트에 정의 된 다른 함수와 충돌 할 가능성이 줄어 듭니다.

var myNamespace = (function () {

  var myPrivateVar, myPrivateMethod;

  // A private counter variable
  myPrivateVar = 0;

  // A private function which logs any arguments
  myPrivateMethod = function( foo ) {
      console.log( foo );
  };

  return {

    // A public variable
    myPublicVar: "foo",

    // A public function utilizing privates
    myPublicFunction: function( bar ) {

      // Increment our private counter
      myPrivateVar++;

      // Call our private method using bar
      myPrivateMethod( bar );

    }
  };

})();

장점

왜 모듈 패턴이 좋은 선택입니까? 초보자에게는 적어도 JavaScript 관점에서 진정한 캡슐화 아이디어보다 객체 지향적 배경에서 개발자가 훨씬 더 깨끗합니다.

둘째, 개인 데이터를 지원하므로 모듈 패턴에서 코드의 공개 부분은 개인 부분을 만질 수 있지만 외부 세계는 클래스의 개인 부분을 만질 수 없습니다.

단점

모듈 패턴의 단점은 공개 멤버와 개인 멤버 모두에 다르게 액세스하므로 가시성을 변경하려면 실제로 멤버가 사용 된 각 위치를 변경해야한다는 것입니다.

또한 나중에 개체에 추가 된 메서드에서 개인 멤버에 액세스 할 수 없습니다 . 즉, 많은 경우에 모듈 패턴은 여전히 ​​매우 유용하며 올바르게 사용되면 응용 프로그램의 구조를 개선 할 수있는 가능성이 있습니다.

공개 모듈 패턴

이제 우리는 모듈 패턴에 좀 더 익숙해 졌으므로 약간 개선 된 버전 인 Christian Heilmann의 Revealing Module 패턴을 살펴 보겠습니다.

공개 모듈 패턴은 Heilmann이 우리가 하나의 공용 메소드를 다른 메소드에서 호출하거나 공용 변수에 액세스하려고 할 때 주 객체의 이름을 반복해야한다는 사실에 좌절하면서 생겨났습니다. 그가 공개하고자하는 것들에 대한 문자 표기법에 반대하는 것.

그의 노력의 결과는 개인 범위에서 모든 함수와 변수를 간단하게 정의하고 공개로 공개하려는 개인 기능에 대한 포인터와 함께 익명 객체를 반환하는 업데이트 된 패턴이었습니다.

공개 모듈 패턴을 사용하는 방법의 예는 아래에 있습니다.

var myRevealingModule = (function () {

        var privateVar = "Ben Cherry",
            publicVar = "Hey there!";

        function privateFunction() {
            console.log( "Name:" + privateVar );
        }

        function publicSetName( strName ) {
            privateVar = strName;
        }

        function publicGetName() {
            privateFunction();
        }


        // Reveal public pointers to
        // private functions and properties

        return {
            setName: publicSetName,
            greeting: publicVar,
            getName: publicGetName
        };

    })();

myRevealingModule.setName( "Paul Kinlan" );

장점

이 패턴을 사용하면 스크립트 구문이보다 일관되게됩니다. 또한 모듈의 끝에서 우리의 기능과 변수 중 어느 것이 공개적으로 액세스 될 수 있는지 더 명확하게하여 가독성을 쉽게합니다.

단점

이 패턴의 단점은 개인 기능이 공용 기능을 참조하는 경우 패치가 필요한 경우 해당 공용 기능을 대체 할 수 없다는 것입니다. 개인 함수는 계속 개인 구현을 참조하고 패턴은 공용 멤버에게 적용되지 않고 함수에만 적용되기 때문입니다.

개인 변수를 참조하는 공용 객체 멤버에도 위의 패치 없음 규칙이 적용됩니다.


9

Erlang의 모듈에서 영감을 얻은 네임 스페이스 를 만들었습니다 . 매우 기능적인 접근 방식이지만 요즘 JavaScript 코드를 작성하는 방법입니다.

클로저에 전역 네임 스페이스를 제공하고 해당 클로저 내에 정의 된 집합 함수를 노출합니다.

(function(){

  namespace("images", previous, next);
  // ^^ This creates or finds a root object, images, and binds the two functions to it.
  // It works even though those functions are not yet defined.

  function previous(){ ... }

  function next(){ ... }

  function find(){ ... } // A private function

})();

8

여러 라이브러리를 다른 프로젝트로 이식하고 최상위 (정적으로 이름이 지정된) 네임 스페이스를 지속적으로 변경 한 후 네임 스페이스를 정의하기 위해이 작은 (오픈 소스) 도우미 함수를 사용하도록 전환했습니다.

global_namespace.Define('startpad.base', function(ns) {
    var Other = ns.Import('startpad.other');
    ....
});

이점에 대한 설명은 내 블로그 게시물에 있습니다. 여기 에서 소스 코드를 얻을 수 있습니다 .

내가 정말로 좋아하는 이점 중 하나는로드 순서와 관련하여 모듈 간 격리입니다. 외부 모듈을로드하기 전에 참조 할 수 있습니다. 코드를 사용할 수있을 때 얻을 수있는 객체 참조가 채워집니다.


1
네임 스페이스 라이브러리의 개선 된 버전 (2.0)을 만들었습니다 : code.google.com/p/pageforest/source/browse/appengine/static/src/…
mckoss

모든 링크가 죽은 것 같습니다
snoob dogg

8

네임 스페이스에 다음 구문을 사용합니다.

var MYNamespace = MYNamespace|| {};

 MYNamespace.MyFirstClass = function (val) {
        this.value = val;
        this.getValue = function(){
                          return this.value;
                       };
    }

var myFirstInstance = new MYNamespace.MyFirstClass(46);
alert(myFirstInstance.getValue());

jsfiddle : http://jsfiddle.net/rpaul/4dngxwb3/1/


8

나는 파티에 7 년 늦었지만이 8 년 전에는 많은 일을했다.

JavaScript 전역 네임 스페이스를 유지하면서 (네임 스페이스 오염 방지) 네임 스페이스 경로의 기존 객체를 방해하지 않으면 서 복잡한 웹 애플리케이션을 구성하고 관리하기 쉽게 중첩 된 여러 네임 스페이스를 쉽고 효율적으로 작성할 수 있어야합니다. .

위의 2008 년 1 월 솔루션입니다.

var namespace = function(name, separator, container){
  var ns = name.split(separator || '.'),
    o = container || window,
    i,
    len;
  for(i = 0, len = ns.length; i < len; i++){
    o = o[ns[i]] = o[ns[i]] || {};
  }
  return o;
};

이것은 네임 스페이스를 생성하는 것이 아니라 네임 스페이스를 생성하는 기능을 제공합니다.

이것은 축소 된 하나의 라이너로 요약 될 수 있습니다.

var namespace=function(c,f,b){var e=c.split(f||"."),g=b||window,d,a;for(d=0,a=e.length;d<a;d++){g=g[e[d]]=g[e[d]]||{}}return g};

사용 예 :

namespace("com.example.namespace");
com.example.namespace.test = function(){
  alert("In namespaced function.");
};

또는 하나의 진술로 :

namespace("com.example.namespace").test = function(){
  alert("In namespaced function.");
};

그런 다음 다음과 같이 실행됩니다.

com.example.namespace.test();

레거시 브라우저에 대한 지원이 필요하지 않은 경우 업데이트 된 버전 :

const namespace = function(name, separator, container){
    var o = container || window;
    name.split(separator || '.').forEach(function(x){
        o = o[x] = o[x] || {};
    });
    return o;
};

이제 namespace전역 네임 스페이스 자체 에 노출 되는 것에 대해 리리가 될 것입니다. (기본 언어가 우리에게 이것을 제공하지 못하는 것은 너무 나쁩니다!) 따라서 나는 일반적으로 다음과 같은 클로저에서 이것을 직접 사용합니다.

(function(){
	const namespace = function(name, separator, container){
		var o = container || window;
		name.split(separator || '.').forEach(function(x){
			o = o[x] = o[x] || {};
		});
		return o;
	};
	const ns = namespace("com.ziesemer.myApp");
	
	// Optional:
	ns.namespace = ns;
	
	// Further extend, work with ns from here...
}());

console.log("\"com\":", com);

더 큰 응용 프로그램에서는 페이지로드 시작시 클라이언트 클라이언트 웹 응용 프로그램의 경우 한 번만 정의하면됩니다. 그런 다음 추가 파일이 유지되면 네임 스페이스 함수를 재사용 할 수 있습니다 (위의 "선택 사항"으로 포함). 최악의 경우,이 함수가 몇 번 다시 선언되면 코드는 몇 줄에 불과하고 축소 된 경우에는 줄어 듭니다.


2

Jaco Pretorius의 솔루션이 마음에 들지만 "this"키워드를 모듈 / 네임 스페이스 객체를 가리켜 서 좀 더 유용하게 만들고 싶었습니다. 스킬 렛의 내 버전 :

(function ($, undefined) {

    console.log(this);

}).call(window.myNamespace = window.myNamespace || {}, jQuery);

2

내가 가장 좋아하는 패턴은 최근에 이렇게되었다 :

var namespace = (function() {
  
  // expose to public
  return {
    a: internalA,
    c: internalC
  }

  // all private
  
  /**
   * Full JSDoc
   */
  function internalA() {
    // ...
  }
  
  /**
   * Full JSDoc
   */
  function internalB() {
    // ...
  }
  
  /**
   * Full JSDoc
   */
  function internalC() {
    // ...
  }
  
  /**
   * Full JSDoc
   */
  function internalD() {
    // ...
  }
  
})();

물론 반환은 끝날 수 있지만 함수 선언 만 뒤에 오는 경우 네임 스페이스가 무엇인지, 어떤 API가 노출되는지 훨씬 쉽게 알 수 있습니다.

이러한 경우 함수 표현식을 사용하는 패턴은 전체 코드를 거치지 않고 어떤 메소드가 노출되는지 알 수 없습니다.


안녕하세요, 스 니펫에서 공개 함수를 어떻게 호출합니까? 나는 시도했다namespace.a();
olimart

@olivier 네, 그 아이디어입니다. ES6에서는 일반적으로 객체 리터럴 ( ponyfoo.com/articles/es6-object-literal-features-in-depth ) 의 속기 구문을 사용합니다.
Nomaed

2

그런 간단한 문제에 대해 너무 많은 코드를 사용한다고 생각합니다. 그에 대한 저장소를 만들 필요가 없습니다. 한 줄 기능이 있습니다.

namespace => namespace.split(".").reduce((last, next) => (last[next] = (last[next] || {})), window);

시도 해봐 :

// --- definition ---
const namespace = namespace => namespace.split(".").reduce((last, next) => (last[next] = (last[next] || {})), window);

// --- Use ----
let myNamespace = namespace("a.b.c");
myNamespace.MyClass = class MyClass {};

// --- see ----
console.log("a : ", a);


1

Makefile을 사용하는 경우이 작업을 수행 할 수 있습니다.

// prelude.hjs
billy = new (
    function moduleWrapper () {
    const exports = this;

// postlude.hjs
return exports;
})();

// someinternalfile.js
function bob () { console.log('hi'); }
exports.bob = bob;

// clientfile.js
billy.bob();

약 1000 줄에 도달하면 Makefile을 사용하는 것이 좋습니다 .makefile에서 한 줄을 제거하여 큰 코드를 효과적으로 주석 처리 할 수 ​​있기 때문입니다. 물건과 함께 쉽게 바이올린을 만들 수 있습니다. 또한이 기술을 사용하면 네임 스페이스가 서곡에 한 번만 나타나므로 변경하기 쉽고 라이브러리 코드 내에서 계속 반복 할 필요가 없습니다.

makefile을 사용할 때 브라우저에서 라이브 개발을위한 쉘 스크립트 :

while (true); do make; sleep 1; done

이것을 make 작업으로 'go'로 추가하면 코딩 할 때 빌드를 최신 상태로 유지하기 위해 'make go'할 수 있습니다.


1

Ionuț G. Stan의 답변에 대한 후속 조치이지만 var ClassFirst = this.ClassFirst = function() {...}동일한 네임 스페이스의 클래스에 대한 네임 스페이스 혼란을 줄이기 위해 JavaScript의 폐쇄 범위를 사용하는을 사용하여 깔끔한 코드의 이점을 보여줍니다 .

var Namespace = new function() {
    var ClassFirst = this.ClassFirst = function() {
        this.abc = 123;
    }

    var ClassSecond = this.ClassSecond = function() {
        console.log("Cluttered way to access another class in namespace: ", new Namespace.ClassFirst().abc);
        console.log("Nicer way to access a class in same namespace: ", new ClassFirst().abc);
    }
}

var Namespace2 = new function() {
    var ClassFirst = this.ClassFirst = function() {
        this.abc = 666;
    }

    var ClassSecond = this.ClassSecond = function() {
        console.log("Cluttered way to access another class in namespace: ", new Namespace2.ClassFirst().abc);
        console.log("Nicer way to access a class in same namespace: ", new ClassFirst().abc);
    }
}

new Namespace.ClassSecond()
new Namespace2.ClassSecond()

산출:

Cluttered way to access another class in namespace: 123
Nicer way to access a class in same namespace: 123
Cluttered way to access another class in namespace: 666
Nicer way to access a class in same namespace: 666

1

패키지 / 단위가 다른 언어로 작동하는 것과 약간 비슷한 다른 네임 스페이스 라이브러리를 작성했습니다. JavaScript 코드 패키지와 다른 코드에서 해당 패키지 참조를 작성할 수 있습니다.

hello.js 파일

Package("hello", [], function() {
  function greeting() {
    alert("Hello World!");
  }
  // Expose function greeting to other packages
  Export("greeting", greeting);
});

파일 Example.js

Package("example", ["hello"], function(greeting) {
  // Greeting is available here
  greeting();  // Alerts: "Hello World!"
});

두 번째 파일 만 페이지에 포함하면됩니다. 의존성 (파일 hello.js 이 예제에서는 )이 자동으로로드되고 해당 종속성에서 내 보낸 객체가 콜백 함수의 인수를 채우는 데 사용됩니다.

Packages JS 에서 관련 프로젝트를 찾을 수 있습니다 .


1
@ peter-mortensen '11 년부터의 답변에 대한 수정 사항이 정말로 필요 했습니까? 그것은 당신이하고있는 일을 훼손하는 것이 아니며 잘못하지는 않지만 매우 피상적입니다. 나는 당신이 정말로 좋은 것을 추가하지 않는 한 이러한 게시물의 유일한 저자로 남아있는 것을 선호합니다.
Stijn de Witt

1

다음과 같이 독립적으로 사용할 수 있습니다.

var A = A|| {};
A.B = {};

A.B = {
    itemOne: null,
    itemTwo: null,
};

A.B.itemOne = function () {
    //..
}

A.B.itemTwo = function () {
    //..
}

0

내 습관은 myName () 함수 를 속성 저장소로 사용하고 var myName 을 "method"홀더로 사용하는 것입니다.

이것이 합법적이든 아니든, 나를 이길! 나는 항상 내 PHP 논리에 의존하고 있으며 일이 간단합니다. :디

function myObj() {
    this.prop1 = 1;
    this.prop2 = 2;
    this.prop3 = 'string';
}

var myObj = (
 (myObj instanceof Function !== false)
 ? Object.create({

     $props: new myObj(),
     fName1: function() { /* code..  */ },
     fName2: function() { /* code ...*/ }
 })
 : console.log('Object creation failed!')
);

if (this !== that) myObj.fName1(); else myObj.fName2();

당신은 또한 객체 생성하기 전에 확인하는 '반대'방법으로 그것을 할 수있는 훨씬 더 :

function myObj() {
    this.prop1 = 1;
    this.prop2 = 2;
    this.prop3 = 'string';
}

var myObj = (
    (typeof(myObj) !== "function" || myObj instanceof Function === false)
    ? new Boolean()
    : Object.create({
        $props: new myObj(),
        init: function () { return; },
        fName1: function() { /* code..  */ },
        fName2: function() { /* code ...*/ }
    })
);

if (myObj instanceof Boolean) {
    Object.freeze(myObj);
    console.log('myObj failed!');
    debugger;
}
else
    myObj.init();

이것에 대한 참조 : JavaScript : Object.create ()로 객체 만들기


0

JavaScript에는 네임 스페이스를 사용하기위한 미리 정의 된 방법이 없습니다. JavaScript에서는 네임 스페이스를 정의하기위한 고유 한 메서드를 만들어야합니다. 다음은 Oodles 기술에서 수행하는 절차입니다.

네임 스페이스 등록 다음은 네임 스페이스를 등록하는 기능입니다.

//Register NameSpaces Function
function registerNS(args){
 var nameSpaceParts = args.split(".");
 var root = window;

 for(var i=0; i < nameSpaceParts.length; i++)
 {
  if(typeof root[nameSpaceParts[i]] == "undefined")
   root[nameSpaceParts[i]] = new Object();

  root = root[nameSpaceParts[i]];
 }
}

네임 스페이스를 등록하려면 이름 공간으로 인수를 '.'점으로 구분하여 위 함수를 호출하십시오 . 예를 들어 응용 프로그램 이름은 oodle입니다. 다음 방법으로 네임 스페이스를 만들 수 있습니다.

registerNS("oodles.HomeUtilities");
registerNS("oodles.GlobalUtilities");
var $OHU = oodles.HomeUtilities;
var $OGU = oodles.GlobalUtilities;

기본적으로 백엔드에서 아래와 같이 네임 스페이스 구조를 만듭니다.

var oodles = {
    "HomeUtilities": {},
    "GlobalUtilities": {}
};

위 함수에서 "oodles.HomeUtilities"and 라는 네임 스페이스를 등록했습니다 "oodles.GlobalUtilities". 이러한 네임 스페이스를 호출하기 위해 변수 var $OHU및 var를 $OGU만듭니다.

이러한 변수는 네임 스페이스 초기화와 별개 일뿐입니다. 이제, 속한 함수를 선언 할 때마다 HomeUtilities다음과 같이 선언합니다.

$OHU.initialization = function(){
    //Your Code Here
};

위의 함수 이름 초기화는 네임 스페이스에 저장 $OHU됩니다. 스크립트 파일의 어느 곳에서나이 함수를 호출합니다. 다음 코드를 사용하십시오.

$OHU.initialization();

마찬가지로 다른 네임 스페이스도 마찬가지입니다.

도움이 되길 바랍니다.


0

JavaScript는 기본적으로 네임 스페이스를 지원하지 않습니다. 따라서 요소 (함수, 메소드, 객체, 변수)를 만들면 전역이되고 전역 네임 스페이스를 오염시킵니다. 네임 스페이스없이 두 함수를 정의하는 예제를 보자.

function func1() {
    console.log("This is a first definition");

}
function func1() {
    console.log("This is a second definition");
}
func1(); // This is a second definition

항상 두 번째 함수 정의를 호출합니다. 이 경우 네임 스페이스는 이름 충돌 문제를 해결합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.