有没有一种“简洁”的方法来在 JavaScript 中进行命名空间?

Is there a "concise" way to do namespacing in JavaScript?

提问人:olliej 提问时间:8/16/2008 最后编辑:Stephen Kingolliej 更新时间:4/20/2018 访问量:3511

问:

我经常遇到一些网站,他们把所有的JavaScript都放在一个结构中,如下所示:namespace

namespaces = { com : { example: { example.com's data} }

但是,相对于其他命名空间框架安全地设置它似乎需要相对较多的代码(定义为 > 2 行)。我想知道是否有人知道一种简洁的方法可以做到这一点?此外,是否有一种相对标准/一致的方法来构建它?例如,命名空间是直接附加到全局对象,还是通过命名空间对象附加?com

[编辑:哎呀,显然不会完成任何接近我预期的事情,感谢 Shog9 指出这一点。{com = { ... } }

JavaScript 命名空间

评论


答:

19赞 Shog9 8/17/2008 #1

Javascript 没有独立的命名空间。它具有函数和对象,前者可以提供解析名称的范围,后者有助于在给定范围内访问命名数据。

这是您的示例,已更正:

var namespaces = { com: { example: { /* example.com's data */ } } }

这是一个被分配对象文字的变量。该对象包含一个属性:,一个具有一个属性的对象:,一个可能包含有趣内容的对象。namespacescomexample

因此,您可以键入类似 namespaces.com.example 的内容。somePropertyOrFunctionOnExample,一切都会起作用。当然,这也是荒谬的。你没有一个分层的命名空间,你有一个对象,它包含一个对象,其中包含一个对象,其中包含你真正关心的东西。

var com_example_data = { /* example.com's data */ };

这同样有效,没有毫无意义的等级制度。

现在,如果你真的建立一个层次结构,你可以尝试这样的东西:

com_example = com_example || {};
com_example.flags = com_example.flags || { active: false, restricted: true};

com_example.ops = com_example.ops || (function()
    {
       var launchCodes = "38925491753824"; // hidden / private
       return {
         activate: function() { /* ... */ },
         destroyTheWorld: function() { /* ... */ }
       };
    })();

...恕我直言,这是相当简洁的。

评论

1赞 Peter 10/4/2011
虽然,现在将成为全局对象的一部分。假设我们添加更多的对象,那么我们仍然污染了全局对象的根层。如果我们在全局中只有一个对象,而所有其他对象都添加了,那不是更可取吗?此外,我们不想覆盖任何现有对象,如果使用了多个库怎么办。com_examplecom_something_elsecom_etccom
2赞 Shog9 10/4/2011
@Peter:如果多个库定义相同的符号,无论如何你都会遇到问题;这就是为什么像jQuery这样的库不遗余力地将所有内容塞进一个全局对象中的原因。我的观点并不是说你应该使用多个顶级对象,只是用深度嵌套的对象伪造命名空间并不能真正让你买到任何东西。请参阅我的最后一个示例,了解一种更实用的方法:使用一个不太可能发生冲突的单个全局名称,然后使用一种允许不同代码位向其添加对象的技术。
3赞 Brendan 8/17/2008 #2

YUI 库库的代码使用您可能认为更可取的函数来处理命名空间。其他库也可以这样做。

12赞 Joseph Pecoraro 8/17/2008 #3

这是 Peter Michaux 关于 Javascript 命名空间的一篇有趣的文章。他讨论了 3 种不同类型的 Javascript 命名空间:

  1. 前缀命名空间
  2. 单个对象命名空间
  3. 嵌套对象命名空间

我不会剽窃他在这里说的话,但我认为他的文章信息量很大。

彼得甚至指出,其中一些存在性能方面的考虑。考虑到新的 ECMAScript Harmony 计划已经放弃了名称空间和打包的 4.0 计划,我认为这个话题会很有趣。

6赞 Polsonby 8/17/2008 #4

我尝试遵循 Yahoo 的惯例,即在全局范围内制作一个父对象来包含所有内容;

var FP = {};
FP.module = {};
FP.module.property = 'foo';
1赞 Mark Cidade 8/18/2008 #5

作为点或下划线的替代方法,您可以使用美元符号字符:

var namespaces$com$example = "data"; 

评论

0赞 eyelidlessness 10/25/2008
这有什么好处?
0赞 Mark Cidade 10/28/2008
通过这种方式,您不必将命名空间定义为具有嵌套内部对象的对象。您可以在任何地方定义名称。
0赞 rodrigo-silveira 2/18/2012
我仍然看不出使用 $ 符号而不是点或下划线的好处。我认为 $ 符号使这个词比点或下划线更难阅读。
0赞 ThiefMaster 3/10/2012
我认为这比使用嵌套对象要糟糕得多 - 你有大量单独的变量 - 无论是全局变量还是局部变量 - 当您查看当前定义的变量时,都会使调试变得地狱。
5赞 Ricky 8/18/2008 #6

为了确保你不会覆盖现有对象,你应该这样做:

if(!window.NameSpace) {
    NameSpace = {};
}

var NameSpace = window.NameSpace || {};

这样,您可以将其放在应用程序/网站中每个文件的顶部,而不必担心覆盖命名空间对象。此外,这将使您能够为每个文件单独编写单元测试。

1赞 dfa 6/19/2009 #7

我也喜欢这个(来源):

(function() {
    var a = 'Invisible outside of anonymous function';
    function invisibleOutside() {
    }

    function visibleOutside() {
    }
    window.visibleOutside = visibleOutside;

    var html = '--INSIDE Anonymous--';
    html += '<br/> typeof invisibleOutside: ' + typeof invisibleOutside;
    html += '<br/> typeof visibleOutside: ' + typeof visibleOutside;
    contentDiv.innerHTML = html + '<br/><br/>';
})();

var html = '--OUTSIDE Anonymous--';
html += '<br/> typeof invisibleOutside: ' + typeof invisibleOutside;
html += '<br/> typeof visibleOutside: ' + typeof visibleOutside;
contentDiv.innerHTML += html + '<br/>';​
0赞 Paul Sweatte 3/24/2012 #8

使用对象文本和对象或显式名称,根据包含函数的局部变量的同级属性执行命名空间。例如:this

var foo = { bar: function(){return this.name; }, name: "rodimus" }
var baz = { bar: function(){return this.name; }, name: "optimus" }

console.log(foo.bar());
console.log(baz.bar());

或者不带 explicit 属性:name

var foo = { bar: function rodimus(){return this; } }
var baz = { bar: function optimus(){return this; } }

console.log(foo.bar.name);
console.log(baz.bar.name);

或者不使用:this

var foo = { bar: function rodimus(){return rodimus; } }
var baz = { bar: function optimus(){return optimus; } }

console.log(foo.bar.name);
console.log(baz.bar.name);

使用 or 构造函数将名称属性添加到计数器变量和其他公用名称,然后使用测试进行检查:RegExpObjecthasOwnProperty

 var foo = RegExp(/bar/);
 
/* Add property */
foo.name = "alpha";

document.body.innerHTML = String("<pre>" + ["name", "value", "namespace"] + "</pre>").replace(/,/g, "&#09;");

/* Check type */
if (foo.hasOwnProperty("name")) 
  {
  document.body.innerHTML += String("<pre>" + ["foo", String(foo.exec(foo)), foo.name] + "</pre>").replace(/,/g, "&#09;");
  }

/* Fallback to atomic value */
else 
  {
  foo = "baz";
  }

var counter = Object(1);

/* Add property */
counter.name = "beta";

if (counter.hasOwnProperty("name")) 
  {
  document.body.innerHTML += String("<pre>" + ["counter", Number(counter), counter.name] + "</pre>").replace(/,/g, "&#09;");
  } 
else 
  {
  /* Fallback to atomic value */
  counter = 0;
  }

DOM 使用以下约定来命名 HTML 和 SVG 元素接口定义:

  • HTMLTitle元素
  • SVGTitle元素
  • SVGScript元素
  • HTMLScript元素

JavaScript 核心使用原型将方法命名为多态的简单形式。toString

引用