JavaScript 命名空间 - 这是一个好的模式吗?

4

目标...

  1. 从全局对象中移除变量、对象等。
  2. 消除冲突的可能性。

首先,我实现了Yahoo命名空间代码(为了举例,我使用ROOT作为我的命名空间根)...

        if (typeof ROOT == "undefined" || !ROOT) {
                var ROOT = {};
        }

        ROOT.namespace = function () {
            var a = arguments,
                o = null,
                i, j, d;
            for (i = 0; i < a.length; i = i + 1) {
                d = ("" + a[i]).split(".");
                o = ROOT;
                for (j = (d[0] == "ROOT") ? 1 : 0; j < d.length; j = j + 1) {
                    o[d[j]] = o[d[j]] || {};
                    o = o[d[j]];
                }
            }
            return o;
        }

现在我声明我的第一个命名空间...
ROOT.namespace("UI");

            ROOT.UI = {
                utc: 12345,
                getUtc: function() {
                    return this.utc;
                }
            }

我在这里想做的是保存我在 UI 中需要的变量(在这种情况下是 UTC 当前时间),以便它们不在全局对象上。我还想提供一些特定功能。这应该在每个页面上都可用,无需任何实例化...
现在我想在我的命名空间结构中存储一个对象。但是,这个对象将需要多次创建。这里的目标是将其保留在我的结构中,但允许根据需要创建多次。具体步骤如下:
 ROOT.namespace("AirportFinder");
            ROOT.AirportFinder = function(){ 
                this.var1 = 99999;

                this.Display = function() {
                    alert(this.var1);
                }            
            }

这是实例化对象的示例代码...
        var test1 = new ROOT.AirportFinder();
        test1.Display();

这是一个好的设计模式吗?
4个回答

1

将事物定义在名称空间ROOT或类似的地方确实是合理的。

使用闭包也更好。

(function() {
    var AirportFinder = function() { 
        this.var1 = 99999;
        this.Display = function() {
            alert(this.var1);
        }            
    };

    // do Stuff with local AirportFinder here.

    // If neccesary hoist to global namespace
    ROOT.AirportFinder = AirportFinder;
}());

如果它们不需要是全局的,我自己使用别名($.foobar,因为jQuery已经是全局的)来存储任何全局数据。

很抱歉我不能告诉你.namespace函数的作用。它并不是真正必要的。

我的个人偏好是始终使用闭包创建私有命名空间,并在必要时将任何内容提升到全局/共享命名空间中。这将全局可见性/集群降至最低。


那么没有命名空间函数代码也能正常工作吗?据我理解,这是一种“定义”命名空间的方式? - Remotec
命名空间方法仅允许长的对象链。也就是说,ROOT.namespace("UI.Airport.Finder") 将创建一个对象 ROOT: {UI: {Airport: {Finder: {}}}},根据需要创建新的对象。如果您只想创建一级子代,则不需要此方法。 - Nathan Ostgard
关于闭包,上述代码是否:一旦脚本加载到浏览器中就立即运行,创建一个声明了我的Airport函数的匿名函数并立即执行它?同时将AirportFinder函数添加到我的ROOT命名空间中?这如何减少全局变量的混乱? - Remotec
@RemotecUK 是的,闭包会立即创建和运行。你应该在闭包中拥有多个私有变量,如果你需要在全局范围内/跨脚本/直接在页面上访问它们,你可以选择将它托管到全局ROOT命名空间中。如果它在全局范围内是必需的,你必须将它提升到某个地方。如果它不需要在全局范围内使用,你就保持它的私有性。 - Raynos

0
稍微引导您一下,离开您的问题的道路: 看看YUI3 (http://developer.yahoo.com/yui/3/) - 在那里你不需要在全局命名空间中有任何东西,你会得到一个私人沙箱。这是一个很好的概念,我喜欢那个库和它的概念(不是旧YUI2)。它的实现方式当然很简单,你也可以这样做: YUI3的动态模块加载器加载你的模块(.js文件),创建一个沙箱(只是一个闭包),并调用你的回调函数,给它一个沙箱句柄。任何其他代码都无法访问该沙箱和你自己的名称。在沙箱内,你可以(也应该)继续使用各种封装模式。这个YUI3的概念对于与外部代码的混搭来说非常好,特别是当混搭变得更加动态(例如用户触发)时,而不仅仅是由程序员自己集成谷歌地图或其他众所周知的API。

0

我尝试做了类似的事情:

var namespace = function(str, root) {
    var chunks = str.split('.');
    if(!root)
        root = window;
    var current = root;
    for(var i = 0; i < chunks.length; i++) {
        if (!current.hasOwnProperty(chunks[i]))
            current[chunks[i]] = {};
        current = current[chunks[i]];
    }
    return current;
};

// ----- USAGE ------

namespace('ivar.util.array');

ivar.util.array.foo = 'bar';
alert(ivar.util.array.foo);

namespace('string', ivar.util);

ivar.util.string.foo = 'baz';
alert(ivar.util.string.foo); 

试一下:http://jsfiddle.net/stamat/Kb5xY/

博客文章:http://stamat.wordpress.com/2013/04/12/javascript-elegant-namespace-declaration/


0
通过使用匿名自执行函数,您可以允许公共和私有属性/方法。
这是我最喜欢的模式:
(function ($, MyObject, undefined) {
  MyObject.publicFunction = function() {
      console.log("This is a public function!");
  };
  var privateFunction = function() {
    console.log("This is a private function!");
  };

  MyObject.sayStuff = function() {
    this.publicFunction();
    privateFunction();
    privateNumber++;
    console.log(privateNumber);
  };
  var privateNumber = 0;

  // You can even nest the namespaces
  MyObject.nestedNamespace = MyObject.nestedNamespace || {};      
  MyObject.nestedNamespace.logNestedMessage = function () {    
     console.log("Nested!!");
  };

}(jQuery, window.MyObject = window.MyObject || {}));

MyObject.sayStuff();
MyObject.nestedNamespace.logNestedMessage();
MyObject.publicFunction();

这篇文章的评论中了解到它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接