创建JavaScript命名空间的最佳方法是什么?

时间:2010-07-18 04:16:09

标签: javascript

我还没有在互联网上找到一种在JavaScript中创建命名空间的常用方法。

创建命名空间的最佳方法是什么(请列出特定方法可能存在的任何缺陷)。

8 个答案:

答案 0 :(得分:7)

(function() {

    var usefulVariable;

    var foo = {
      bar:function(){ alert('hi') }
    };

    // leak into global namespace
    window.foo = foo;

})();

只有foo暴露给全局命名空间,并且它“存在”私有自执行匿名函数命名空间内。

答案 1 :(得分:7)

在JavaScript中,名称空间只能通过对象文字来实现,这可以像这样简单:

var MyNS = {
    f1: function() {...},
    f2: function() {...}
};

正如其他人试图展示的那样,如果你想在你的命名空间中提供一个私有范围(建议),下面的方法是最合适的:

var MyNS = (function() {
    var private1 = "...", 
        private2 = "...";

    return {
        f1: function() {...},
        f2: function() {...}
    }
})();

答案 2 :(得分:4)

Pro JavaScript Design Patterns(Harmes& Diaz,2008)一书提供了使用简单对象文字或自动执行匿名函数创建命名空间的示例,这些都在Justin Johnson的优秀答案中有所说明,并且这些方法运行良好。

根据具体情况,命名空间可能已存在且包含成员。在这种情况下,这些方法会破坏命名空间中的任何成员。如果这是一个问题,可以使用类似于此的方法来保留任何现有成员,同时添加新成员:

var myNamespace = (function(ns) {
    ns.f1 = function() { ... };
    ns.f2 = function() { ... };

    return ns;
})(window.myNamespace || {});

这里,myNamespace被赋予接收参数ns的匿名自执行函数返回的值。可以看出,此参数的值是window.myNamespace或空对象,具体取决于myNamespace是否先前已声明过。

答案 3 :(得分:1)

这是我最喜欢的方式。这有点不正统,但效果很好。

  var MyNamespace = new function(){

    this.MY_CONST_ONE = 1;
    this.MY_CONST_TWO = 2;

    this.MyClass = function (x) {
      this.x = x;
    }

    this.MyOtherClass = function (y) {
      this.y = y;
    }

  } // end of namespace

  // ... 

  var oc = new MyNamespace.MyOtherClass(123);

有趣的是,闭包函数是用new而不是普通的括号调用的,所以直接在它内部this指的是函数返回的对象,换句话说, '命名空间'本身。

答案 4 :(得分:1)

我通常会尝试保持简单,并创建一个表示命名空间的全局对象。如果您使用多个脚本,每个脚本都声明命名空间,因为它们可能分别用于不同的应用程序,那么您可能想要检查该对象是否已经存在。

//create the namespace - this will actually obliterate any pre-existing 
//object with the same name in the global namespace 
//(and this does happen). 
//NB ommiting the var keyword automatically chucks the object
//variable into the global namespace - which ordinarily you
//don't want to do 
MyNameSpace = {};

//and then create a class/object in the namespace
MyNameSpace.MyClass = {

            someProperty: function(){
                //do something

            },
            anotherProperty: function(){
                //doing something else
            }


};

这几乎是其他人所说的。我只是给出了非常简单的方法。我看到的主要缺点是理论上“MyNameSpace”对象可能已经存在 - 因此可能需要在创建它之前检查它。一般来说,如果我要做一些比这更复杂的事情,我会开始考虑像JQuery或ExtJS这样的框架,这些框架会带来很多痛苦。

还有一点需要注意。你无法找到在Javascript中做很多事情的常用方法的部分原因,比如创建命名空间,是因为总有不止一种方法可以在Javascript中对猫进行换肤。大多数语言对你的工作方式都很苛刻 - 创建类,功能或面向对象或程序。另一方面,Javascript缺少关键字且高度灵活。这可能是件好事还是坏事 - 取决于你的观点。但我非常喜欢它。

答案 5 :(得分:1)

要在脚本之间共享代码,您必须至少拥有一个全局变量(当然,除非您想要做一些愚蠢的事情,如将变量附加到已存在的对象,例如window.Object

即使您使用模块模式,您也需要有一个共同的位置来共享代码,例如,例如你有三个脚本:

  • core.js
  • utils.js

然后我们可以在core.js脚本文件中有一个模块:

(function(global) {
    var coreModule = {};

    var MY_CONSTANT = 42

    var meaningOfLife = function() {
        return MY_CONSTANT;
    };
    coreModule.meaningOfLife = meaningOfLife;

    global.myRootNamespace = coreModule;
}(this));
utils.js中的

(function(root) {
    var utilsModule = root.utils = {};

    utilsModule.bark = function() {
        console.log("WOOF!");
    };
}(myRootNamespace));

在这里,我们看到增强模块模式的使用,并根据功能的性质命名功能。此特定实现将覆盖utils对象上myRootNamespace属性的值。但是,我们可以编写它以便它不会:

(function(root) {
    var utilsModule = root.utils = root.utils || {};

    utilsModule.bark = function() {
        console.log("WOOF!");
    };
}(myRootNamespace));

如果不想使用模块模式,我们可以使用一个简单的函数以非破坏性方式为我们定义命名空间:

var ensureNamespace = function recur(ns, root) {
    var parts = typeof ns === 'string' ? ns.split('.') : ns;

    var r = root || this;

    if (parts[0]) {
        var next = parts.shift()
        r[next] = r[next] || {};
        return recur(parts, r[next]);
    }

    return r;
};

// maybe another file:
(function(){
    var baz = ensureNamespace("foo.bar.baz");
    // baz === window.foo.bar.baz;

    baz.qux = "Yep...";
}());

请参阅this excellent article了解更多信息。

答案 6 :(得分:0)

您可以结合到目前为止收到的答案并取得很大成就;

var Foo;  // declare in window scope.

(function(){

   var privateVar = "BAR!";

   // define in scope of closure where you can make a mess that 
   // doesn't leak into the window scope.

   Foo = {
      staticFunc: function(){ return privateVar; }
   };

})();

我通常会避免使用window.xxxx = yyyy;,因为它并不能很好地与visual studio intellesense很好地配合。可能还有其他问题但我不知道。

答案 7 :(得分:0)

我相信模块模式已经表明它是要走的路。 Object Literal Name-spacing将所有内容暴露给命名空间之外的调用者代码,这本质上不是一个好主意。

如果您坚持创建Object Literal命名空间,请阅读本教程。我觉得这很容易也很简短,我相信很顺利:Object Literal Namespace (OLN) in Javascript