使用JavaScript命名空间有任何危险吗?

时间:2012-01-18 20:02:59

标签: javascript jquery version-control namespaces project-management

创建JavaScript命名空间时是否应该注意任何危险/警告?

我们的项目相当广泛,我们运行了很多JavaScript文件(20多个,期待更多)。如果不使用名称空间,就不可能有任何代码可维护性,所以我们就像这样实现它们:

var namespace1 = {

  doSomething: function() {
    ...
  },

  doSomethingElse: function() {
    ...
  }

}

然后创建层次结构,我们将它们链接起来:

var globalNamespace = {
  functions1: namespace1,
  functions2: namespace2,
  ...

}

这很好,但它本质上是一个“技巧”,使JS的行为就像它确实有名称空间一样。尽管这种方法得到了很多应用,但大多数关于此的文献似乎都集中在如何做到这一点,而不是是否存在任何可能的缺点。随着我们编写更多JS代码,这很快就会成为我们系统工作方式的一个组成部分。因此,它无缝地工作非常重要。

是否存在这种“诱导”命名空间系统导致错误或需要特别注意的情况?我们可以安全地期望所有浏览器都有相同的行为吗?

4 个答案:

答案 0 :(得分:3)

您在示例中定义名称空间的方式似乎是从每个名称空间中创建全局变量,因此您最终会使用

window.namespace1
window.namespace2
window.globalNamespace
window.globalNamespace.namespace1
window.globalNamespace.namespace2

所以,如果你有任何破坏者window.namespace1它也会破坏window.globalNamespace.namespace1

编辑:

以下是我们解决这个问题的方法:

namespacing = {
    init: function(namespace) {
        var spaces = []; 
        namespace.split('.').each(function(space) {
            var curSpace = window,
                i;  

            spaces.push(space);
            for (i = 0; i < spaces.length; i++) {
                if (typeof curSpace[spaces[i]] === 'undefined') {
                    curSpace[spaces[i]] = {}; 
                }   
                curSpace = curSpace[spaces[i]];
            }   
        });
    }
};

然后你就这样使用它:

namespacing.init('globalNamespace.namespace1');

globalNamespace.namespace1.doSomething = function() { ... };

这样您就不必引入新的全局变量,并且可以放心地添加到现有的命名空间而不会破坏其中的其他对象。

答案 1 :(得分:2)

由于您基本上是将对象和这些对象的函数添加到其他对象中,我希望每个浏览器都能以相同的方式处理它。

但是如果你想要模块化,为什么不使用像require.js这样的(相对)简单的框架呢?这将允许您和您的团队以模块化方式编写代码,并允许团队在需要时“导入”这些模块:

require(["helper/util"], function() {
  //This function is called when scripts/helper/util.js is loaded.
});

Require.js将处理依赖关系,它还可以防止污染全局命名空间。

答案 2 :(得分:1)

我们在工作中使用类似的系统,它可以很好地完成工作。我没有看到任何可能的缺点;它只是对象和属性。出于同样的原因,跨浏览器兼容性应该是好的。您最终可能需要编写一些长名称来解析特定函数,例如Foo.Bar.Test.Namespace2.Function,但即便如此,也可以通过将其分配给变量来解决。

答案 3 :(得分:1)

这就是我建议的方式,因此除了“基本”命名空间外,你完全不在全球范围内。我们在工作的地方做类似的事情。假设您为Acme co工作,并希望ACME成为您的基本命名空间。

在每个文件的顶部,您都包含:

if (!window.ACME) { window.ACME = {} }

然后你就可以根据需要定义你想要的任何东西。

ACME.Foo = {
  bar: function () { console.log("baz"); }
}

如果你想要更深层次的命名空间,你只需为每个级别做同样的事情。

if (!window.ACME) { window.ACME = {} }
if (!ACME.Foo) { ACME.Foo = {} }

这样每个文件都可以独立测试,并且它们会自动设置命名空间基础结构,但是当你一起编译它们或者你同时测试多个文件时,它们不会覆盖已经定义的东西。