什么';创建JavaScript名称空间的最佳方法是什么?

什么';创建JavaScript名称空间的最佳方法是什么?,javascript,Javascript,我还没有在互联网上找到用JavaScript创建名称空间的通用方法 创建名称空间的最佳方法是什么(请列出该特定方法可能存在的任何缺点) 只有foo暴露于全局名称空间,并且它“存在”于您的私有自动执行的非函数名称空间中。您可以将迄今为止收到的答案组合在一起,并完成许多工作 var Foo; // declare in window scope. (function(){ var privateVar = "BAR!"; // define in scope of closure

我还没有在互联网上找到用JavaScript创建名称空间的通用方法

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


只有
foo
暴露于全局名称空间,并且它“存在”于您的私有自动执行的非函数名称空间中。

您可以将迄今为止收到的答案组合在一起,并完成许多工作

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配合使用。可能还有其他问题,但据我所知,没有任何问题。

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

var MyNS = {
    f1: function() {...},
    f2: function() {...}
};
正如其他人试图展示的那样,如果您希望在名称空间中提供私有范围(建议使用),以下方法最合适:

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

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

这是我最喜欢的方式。这有点离经叛道,但效果很好

  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
调用的,而不是普通的括号,因此直接在它的内部
这个
指的是函数返回的对象,换句话说,就是“名称空间”本身。

Pro JavaScript设计模式一书(Harmes&Diaz,2008)提供了使用简单对象文本或自动执行匿名函数创建名称空间的示例,Justin Johnson的优秀回答中对这两种方法进行了说明,这些方法效果良好

根据情况,名称空间可能已经存在并包含成员。在这种情况下,这些方法将销毁名称空间中的任何成员。如果这是一个问题,可以使用类似的方法保留任何现有成员,同时添加新成员:

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

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

在这里,myNamespace被分配由接收参数ns的匿名自动执行函数返回的值。可以看出,此参数的值是window.myNamespace或空对象,这取决于之前是否声明了myNamespace。

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

//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缺少关键字,并且非常灵活。这可能是好事,也可能是坏事——取决于你的观点。但是我非常喜欢它。

我相信模块模式已经表明了这是一条路要走。对象文字名称间距向命名空间之外的调用方代码公开所有内容,这从本质上讲不是一个好主意


如果您坚持创建对象文字名称空间,请阅读本教程。我发现这很简单,而且我相信这很简单:

要在脚本之间共享代码,您必须至少有一个全局变量(当然,除非您想做一些愚蠢的事情,比如将变量附加到一个已经存在的对象,例如
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));
这里,我们看到了增强模块模式的使用,以及根据功能的性质对功能进行命名。此特定实现覆盖了
myRootNamespace
对象上
utils
属性的值。但是,我们可以编写它,使其不会:

(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...";
}());

有关详细信息,请参阅。

因此,如果我想调用“bar”函数,我将如何执行该操作?window.foo.bar()?只要调用
foo.bar
。如果我没有通过
window.foo
公开它,那么
foo
只能在该函数内部访问。一旦设置了window,你就失去了使用名称空间的目的。@Dan-你不必公开它,我只是在演示它的某些方面。为什么不
this.foo=foo
,since
window
是非标准的,您仍然处于全局范围内?就此而言,为什么不
this.foo={…
而不是
var foo={…
?“名称空间只能通过对象文本实现”-那不是真的。对象文字只是创建对象的一种方法,但其他对象创建方法也可以用于“名称空间”目的。你有例子吗?你可以使用构造函数(用new调用),或者用new对象创建空对象,然后逐个添加属性。(我并不是说这些技术比使用对象文字更好,我只是反对你所说的需要对象文字。)
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...";
}());