JavaScript名称空间-寻找一种简单高效的方法

JavaScript名称空间-寻找一种简单高效的方法,javascript,jquery,javascript-framework,Javascript,Jquery,Javascript Framework,我想在一个项目中实现JavaScript名称空间。我和我的同事不是JavaScript方面的专家,因此我们正在寻找一种简单高效的名称空间方法。可读性是一项巨大的资产,我们是Java开发人员,很容易成为JavaScript陷阱的猎物 我们编写了以下概念证明: <html><body><script> var mynamespace = {}; mynamespace.variable = "inside mynamespace"; mynamespace.lev

我想在一个项目中实现JavaScript名称空间。我和我的同事不是JavaScript方面的专家,因此我们正在寻找一种简单高效的名称空间方法。可读性是一项巨大的资产,我们是Java开发人员,很容易成为JavaScript陷阱的猎物

我们编写了以下概念证明:

<html><body><script>
var mynamespace = {};
mynamespace.variable = "inside mynamespace";
mynamespace.level1 = {};
mynamespace.level1.level2 = {};

(function(){
    this.variable = "inside mynamespace.level1";
    this.print = function(){ return "print() : " + this.variable };
}).apply(mynamespace.level1);

(function(){
    this.variable = "inside mynamespace.level1.level2";
    this.print = function(){ return "print() : " + this.variable };
}).apply(mynamespace.level1.level2);

// We can use "that" instead of "this"; however I do not see any benefit in doing it...
(function(){
    if(!mynamespace.level1.level2b){ this.level2b = {}; var that = this.level2b };
    that.variable = "inside mynamespace.level1.level2b";
    that.print = function(){ return "print() : " + this.variable };
}).apply(mynamespace.level1);

document.write(mynamespace.level1.print() + "<br>"); // print() : inside mynamespace.level1
document.write(mynamespace.level1.variable + "<br>");// inside mynamespace.level1

document.write(mynamespace.level1.level2.print() + "<br>");// print() : inside mynamespace.level1.level2
document.write(mynamespace.level1.level2.variable + "<br>");// inside mynamespace.level1.level2

document.write(mynamespace.level1.level2b.print() + "<br>");// print() : inside mynamespace.level1.level2b
document.write(mynamespace.level1.level2b.variable + "<br>");// inside mynamespace.level1.level2b

document.write(mynamespace.variable + "<br>");// inside mynamespace
document.write(mynamespace.something + "<br>");// undefined
</script></body></html>

var mynamespace={};
mynamespace.variable=“在mynamespace内部”;
mynamespace.level1={};
mynamespace.level1.level2={};
(功能(){
this.variable=“在mynamespace.level1内部”;
this.print=function(){return“print():”+this.variable};
}).apply(mynamespace.level1);
(功能(){
this.variable=“在mynamespace.level1.level2内部”;
this.print=function(){return“print():”+this.variable};
}).apply(mynamespace.level1.level2);
//我们可以用“那个”代替“这个”;然而,我认为这样做没有任何好处。。。
(功能(){
如果(!mynamespace.level1.level2b){this.level2b={};var that=this.level2b};
that.variable=“在mynamespace.level1.level2b内部”;
that.print=function(){return“print():”+this.variable};
}).apply(mynamespace.level1);
document.write(mynamespace.level1.print()+“
”);//print():在mynamespace.level1中 document.write(mynamespace.level1.variable+“
”);//在mynamespace.level1中 document.write(mynamespace.level1.level2.print()+“
”);//print():在mynamespace.level1.level2内 document.write(mynamespace.level1.level2.variable+“
”);//在mynamespace.level1.level2内 document.write(mynamespace.level1.level2b.print()+“
”);//print():在mynamespace.level1.level2b内 document.write(mynamespace.level1.level2b.variable+“
”);//在mynamespace.level1.level2b中 document.write(mynamespace.variable+“
”);//在mynamespace内 document.write(mynamespace.something+“
”);//未定义
==问题===

问题1。你认为这是一个好方法吗

问题2。我们会遇到什么陷阱吗

第三季度。你有更好的建议吗?(请考虑简单性,可读性) 非常感谢您的帮助

干杯

编辑:
我们将使用jQuery。所以,有一个更好的方法使用jQuery,我们会考虑它。

,即使对于简单的项目,我也总是使用JavaScript命名空间。我使用以下名称空间模式(在JavaScript模式中找到):

在团队中工作时,以这种方式创建名称空间是一种很好的方法——没有人会覆盖您的名称空间。此外,您还可以轻松地指定团队创建名称空间的位置(文件),这样就可以很容易地看到使用了什么名称

然后,如果需要,我将使用闭包来分离对象的私有上下文(在示例中也是如此)。闭包可能是JS(函数式编程)中最强大的工具。您可以创建持续到删除每个内部对象的上下文

我也喜欢和启示模式(它与
new
一起工作,也不与之一起工作):


还可以阅读我一开始提到的那本书——我个人认为这是用JS编程时最佳实践的来源。我从这本书中学到了很多

就个人而言,我认为你已经做得很好了,只是有些小事情需要改进。首先,您应该将名称空间移动到一个单独的文件中,而不是像这样将其与您的工作放在同一个文件中。我建议您将其放在
namespace.js
中。接下来,名称空间也是非常重要的,您应该检查当前名称空间是否存在。上面的代码总是声明新变量。这是一个相当严重的问题,特别是当您的同事已经声明了名称空间并将一些属性放入该名称空间时,您的代码将完全覆盖您的同事,并且在提取同事的代码时,您将始终出错。我建议:

namespace.js中

var window.MyNameSpace = window.MyNameSpace || {};
MyNameSpace.variable = "inside mynamespace";
MyNameSpace.level1 = MyNameSpace.level1 || {};
MyNameSpace.level1.level2 = MyNameSpace.level1.level2 || {};
因此,当您的同事已经声明了名称空间或向现有名称空间添加了一些属性时,它不会覆盖现有名称空间。假设您的同事已经创建了
MyNameSpace
,并添加了
MyNameSpace.level1=something
。上面的代码不会覆盖
MyNameSpace
MyNameSpace.level1
,它只指向当前现有的名称空间及其属性

注意您必须在其他js文件之前包含namespace.js,否则会出现
未定义
错误


希望这有帮助

我可以看到一些快速的问题

考虑这一点:

var car = {};
car.manufacturer = "Toyota";
car.doors = 4;
car.format = "sedan";
car.wheels = 4;
这里有很多重复发生。
如果您试图使其成为一个进一步的嵌套对象,但继续以这种方式定义属性,那么将需要大量的重新键入或复制/粘贴

var garage = {};
garage.cars = [];
garage.cars[0] = {};
garage.cars[0].doors = 4;
garage.cars[0].drivers = [];
garage.cars[0].drivers[0].name = "Bob";
…等等

这里的第一个问题是,以这样或那样的形式,很容易忽略细节。行太多,重复太多,可能在第37行中,您忘记初始化
汽车[3]。驾驶员[1]。车牌号

第二个问题是,如果您中断了此初始化,但尝试按照定义不好的顺序进行初始化(即:在多个JS文件上执行此操作,或在多个AJAX调用上执行此操作),那么当您尝试向尚未存在的成员添加属性时,可能会遇到异常

//核心js var MyApp={}; MyApp.modules={}

//js#2在js#1之前加载 MyApp.modules.myModule.subModule={};//将抛出异常

//js#1 MyApp.modules.myModule={}

有很多方法可以解决这个问题,但它们都取决于您希望实现的目标:

如果您正在构建具有静态默认值的数据结构,那么我建议您构建一个简单的数据结构,如下所示:

SN.namespace('SN.subnamespace1.subnamespace3');
SN.subnamespace1.subnamespace3.object = function() {};
var car = {
    doors : 4,
    manufacturer : "Toyota"
};
或者像这样更精细的物体:

var garage = {
    cars : [
        {
            doors : 2,
            drivers : [
                { name : "Bob", age : 32 },
                { name : "Susanne", age : 18 }
            ]
        }
    ]
};
他们可以性病
var car = {
    doors : 4,
    manufacturer : "Toyota"
};
var garage = {
    cars : [
        {
            doors : 2,
            drivers : [
                { name : "Bob", age : 32 },
                { name : "Susanne", age : 18 }
            ]
        }
    ]
};
garage.cars[0].drivers[1].name; // Susanne
if (MyApp && MyApp.modules.myModule) {
    MyApp.modules.myModule.subModule = {
        send : function () { }
    };
}
namespace("MyApp.modules.myModule.subModule.addOn", { method : function () {},
                                                      property_1 : 1,
                                                      property_2 : false       });
function decrease_fuel () { this.fuel -= 1; }

var car = {
    fuel : 100,
    speed : 10,
    pos  : { long : ..., lat : ... },
    dir  : { long : ..., lat : ... },
    drive : function () {
        if (this.fuel > 0) {
            this.pos.long += this.dir.long * this.speed;
            this.pos.lat  += this.dir.lat  * this.speed;
            decrease_fuel(); // whoops! `this === window`
            // decrease_fuel.call(this); would work
        }
    }
};
var outer = function () {
    var that = this,
        inner = function () { console.log(that); };
    inner();
};

outer.call({ name : "Bob" }); // logs bob object
outer.call({ name : "Bob" }); // would log `window` object