在JavaScript中如何声明命名空间?

1074

如何创建JavaScript中的命名空间,以便我的对象和函数不会被其他同名的对象和函数覆盖?我已经使用了以下代码:

if (Foo == null || typeof(Foo) != "object") { var Foo = new Object();}

有没有更优雅或更简洁的方法来做这件事?


21
我能理解你的想法,即检查命名空间是否被占用,但由于如果此操作失败,对象将不会被创建,因此我认为更好的方法是在命名空间已被占用时发出警告。坦白地说,在大多数 JavaScript 情况下,这种情况应该不会发生,并且应该很快在开发过程中被捕获。 - annakata
19
拥有一个顶层“命名空间”(窗口属性)。早期测试应该能够检测到冲突。不要费心添加所有这些“如果”的检查。重复的“命名空间”是致命问题,应该像这样处理。你可以像jQuery一样采取一种方法来允许使用自定义“命名空间”,但这仍然是设计时的问题。 - user166390
请参见 https://dev59.com/PkvSa4cB1Zd3GeqPeXKv 以了解 JavaScript 命名空间技术的性能问题。 - Tim Abell
请参见https://dev59.com/Am855IYBdhLWcg3w0H93,了解有关JavaScript中使用对象和函数命名空间的区别。 - Tim Abell
这是大量的信息,但真正阐述了不同JS设计模式之间的差异。它对我帮助很大:http://addyosmani.com/resources/essentialjsdesignpatterns/book/ - Justin
1
现在我们有符号和模块,所以重复的命名空间甚至不应该成为一个问题。 - Sebastian Simon
29个回答

2

我喜欢Jaco Pretorius的解决方案,但我想通过将"this"关键字指向模块/命名空间对象使其更有用。

我的版本:

(function ($, undefined) {

    console.log(this);

}).call(window.myNamespace = window.myNamespace || {}, jQuery);

1

我写了另一个命名空间库,它的工作方式更像其他语言中的包/单元。它允许您创建一个JavaScript代码包,并从其他代码引用该包:

文件 hello.js

Package("hello", [], function() {
  function greeting() {
    alert("Hello World!");
  }
  // Expose function greeting to other packages
  Export("greeting", greeting);
});

文件 Example.js

Package("example", ["hello"], function(greeting) {
  // Greeting is available here
  greeting();  // Alerts: "Hello World!"
});

只需要在页面中包含第二个文件。它的依赖项(例如本例中的hello.js文件)将自动加载,并且从这些依赖项导出的对象将用于填充回调函数的参数。

您可以在Packages JS中找到相关项目。


1
@peter-mortensen,这些对我在'11年的回答的编辑真的有必要吗?你所做的绝对不是破坏行为,别误会了,但它们非常肤浅。除非你真的添加了一些好的东西,否则我更愿意保持像这样的帖子的唯一作者身份。 - Stijn de Witt

1
相当于Ionuț G. Stan的回答,但通过使用var ClassFirst = this.ClassFirst = function() {...}展示了简洁代码的好处,利用JavaScript的闭包作用域减少了同一命名空间下类的名称冲突。
var Namespace = new function() {
    var ClassFirst = this.ClassFirst = function() {
        this.abc = 123;
    }

    var ClassSecond = this.ClassSecond = function() {
        console.log("Cluttered way to access another class in namespace: ", new Namespace.ClassFirst().abc);
        console.log("Nicer way to access a class in same namespace: ", new ClassFirst().abc);
    }
}

var Namespace2 = new function() {
    var ClassFirst = this.ClassFirst = function() {
        this.abc = 666;
    }

    var ClassSecond = this.ClassSecond = function() {
        console.log("Cluttered way to access another class in namespace: ", new Namespace2.ClassFirst().abc);
        console.log("Nicer way to access a class in same namespace: ", new ClassFirst().abc);
    }
}

new Namespace.ClassSecond()
new Namespace2.ClassSecond()

输出:

Cluttered way to access another class in namespace: 123
Nicer way to access a class in same namespace: 123
Cluttered way to access another class in namespace: 666
Nicer way to access a class in same namespace: 666

1
在JavaScript中,没有预定义的命名空间使用方法。在JavaScript中,我们必须创建自己的方法来定义命名空间。以下是Oodles技术遵循的过程。
注册一个命名空间 以下是注册命名空间的函数。
//Register NameSpaces Function
function registerNS(args){
 var nameSpaceParts = args.split(".");
 var root = window;

 for(var i=0; i < nameSpaceParts.length; i++)
 {
  if(typeof root[nameSpaceParts[i]] == "undefined")
   root[nameSpaceParts[i]] = new Object();

  root = root[nameSpaceParts[i]];
 }
}

要注册一个命名空间,只需调用上述函数并将参数设置为由'.'(点)分隔的命名空间名称即可。 例如:假设您的应用程序名称为oodles。您可以通过以下方法创建一个命名空间。
registerNS("oodles.HomeUtilities");
registerNS("oodles.GlobalUtilities");
var $OHU = oodles.HomeUtilities;
var $OGU = oodles.GlobalUtilities;

基本上它会在后端创建以下的命名空间结构:
var oodles = {
    "HomeUtilities": {},
    "GlobalUtilities": {}
};

在上面的函数中,您注册了名为"oodles.HomeUtilities""oodles.GlobalUtilities"的命名空间。要调用这些命名空间,我们使用变量,即var $OHU和var $OGU
这些变量只是初始化命名空间的别名。 现在,每当您声明属于HomeUtilities的函数时,将像以下方式声明:
$OHU.initialization = function(){
    //Your Code Here
};

上面是函数名称初始化,并将其放入命名空间$OHU中。在脚本文件的任何地方调用此函数,只需使用以下代码。
$OHU.initialization();

同样地,还有另一个命名空间。希望能对你有所帮助。

1

JavaScript目前尚未拥有本地名称空间的表示方式,但TypeScript已经支持了。

例如,您可以使用以下TS代码(playground

namespace Stack {
    export const hello = () => console.log('hi')
}

Stack.hello()

如果您无法将代码更新为TS,那么您至少可以使用TS在命名空间生成JS输出时所采用的模式,其格式如下:

var Stack;
(function (Stack) {
    Stack.hello = () => console.log('hi');
})(Stack || (Stack = {}));
Stack.hello();

更多阅读:


1
如果使用Makefile,你可以这样做。
// prelude.hjs
billy = new (
    function moduleWrapper () {
    const exports = this;

// postlude.hjs
return exports;
})();

// someinternalfile.js
function bob () { console.log('hi'); }
exports.bob = bob;

// clientfile.js
billy.bob();

一旦代码超过1000行,我更喜欢使用Makefile,因为我可以通过在Makefile中删除一行来有效地注释掉大量的代码。这使得调试变得容易。此外,使用这种技术,命名空间只出现在前言中一次,所以很容易更改,而且不必在库代码中重复它。

使用Makefile进行浏览器实时开发的Shell脚本:

while (true); do make; sleep 1; done

将此内容添加为“make”任务,然后您可以使用“make go”命令在编码时保持构建更新。

1
我们可以这样独立使用它:

var A = A|| {};
A.B = {};

A.B = {
    itemOne: null,
    itemTwo: null,
};

A.B.itemOne = function () {
    //..
}

A.B.itemTwo = function () {
    //..
}

0

我的习惯是使用函数myName()作为属性存储,然后使用var myName作为"方法"的容器...

无论这是否足够合法,都打我吧!我一直依赖我的PHP逻辑,事情就这么简单。:D

function myObj() {
    this.prop1 = 1;
    this.prop2 = 2;
    this.prop3 = 'string';
}

var myObj = (
 (myObj instanceof Function !== false)
 ? Object.create({

     $props: new myObj(),
     fName1: function() { /* code..  */ },
     fName2: function() { /* code ...*/ }
 })
 : console.log('Object creation failed!')
);

if (this !== that) myObj.fName1(); else myObj.fName2();

你也可以以“反之亦然”的方式进行检查,以在对象创建之前进行检查,这种方式更好

function myObj() {
    this.prop1 = 1;
    this.prop2 = 2;
    this.prop3 = 'string';
}

var myObj = (
    (typeof(myObj) !== "function" || myObj instanceof Function === false)
    ? new Boolean()
    : Object.create({
        $props: new myObj(),
        init: function () { return; },
        fName1: function() { /* code..  */ },
        fName2: function() { /* code ...*/ }
    })
);

if (myObj instanceof Boolean) {
    Object.freeze(myObj);
    console.log('myObj failed!');
    debugger;
}
else
    myObj.init();

参考此链接:使用Object.create()创建JavaScript对象


0

JavaScript默认不支持命名空间。因此,如果您创建任何元素(函数、方法、对象、变量),它将成为全局变量并污染全局命名空间。让我们举一个没有任何命名空间定义两个函数的例子:

function func1() {
    console.log("This is a first definition");

}
function func1() {
    console.log("This is a second definition");
}
func1(); // This is a second definition

它总是调用第二个函数定义。在这种情况下,命名空间将解决名称冲突问题。


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