如何在JavaScript中创建命名空间,使我的对象和函数不被其他同名对象和函数覆盖?我使用了以下方法:

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

有没有更优雅或更简洁的方式来做到这一点?


当前回答

如果使用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任务“go”,您可以“make go”以在编写代码时保持构建的更新。

其他回答

虽然我已经晚了7年,但是在8年前我已经为此做了很多工作:

http://blogger.ziesemer.com/2008/05/javascript-namespace-function.html http://blogger.ziesemer.com/2007/10/respecting-javascript-global-namespace.html

能够轻松有效地创建多个嵌套的名称空间,以保持复杂的web应用程序的组织和管理,同时尊重JavaScript全局名称空间(防止名称空间污染),并且在这样做的时候不破坏名称空间路径中的任何现有对象,这是很重要的。

以上是我在2008年前后的解决方案:

var namespace = function(name, separator, container){
  var ns = name.split(separator || '.'),
    o = container || window,
    i,
    len;
  for(i = 0, len = ns.length; i < len; i++){
    o = o[ns[i]] = o[ns[i]] || {};
  }
  return o;
};

这不是创建名称空间,而是提供了创建名称空间的函数。

这可以浓缩成一个简化的一行代码:

var namespace=function(c,f,b){var e=c.split(f||"."),g=b||window,d,a;for(d=0,a=e.length;d<a;d++){g=g[e[d]]=g[e[d]]||{}}return g};

使用示例:

namespace("com.example.namespace");
com.example.namespace.test = function(){
  alert("In namespaced function.");
};

或者,作为一种说法:

namespace("com.example.namespace").test = function(){
  alert("In namespaced function.");
};

然后执行如下:

com.example.namespace.test();

如果你不需要支持旧浏览器,更新版本:

const namespace = function(name, separator, container){
    var o = container || window;
    name.split(separator || '.').forEach(function(x){
        o = o[x] = o[x] || {};
    });
    return o;
};

现在,我对将命名空间暴露给全局命名空间本身持谨慎态度。(可惜基础语言没有为我们提供这个!)所以我通常会在闭包中使用这个,比如:

(函数(){ Const namespace = function(名称,分隔符,容器){ Var o =容器||窗口; 的名字。split(separator || '.'). foreach(函数(x){ O = O [x] = O [x] || {}; }); 返回啊; }; const ns = namespace("com.ziesemer.myApp"); / /可选: ns.namespace = ns; //进一步扩展,使用ns从这里… } ()); console.log (\ com \”:“com);

在较大的应用程序中,这只需要在页面加载开始时定义一次(对于基于客户端的web应用程序)。如果保留的话,其他文件可以重用命名空间函数(在上面包含为“可选”)。在最坏的情况下,如果这个函数被重新声明了几次——它只需要几行代码,如果简化了,就会更少。

我写了另一个命名空间库,它的工作方式有点像其他语言中的包/单元。它允许你创建一个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中找到相关的项目。

因为您可能会编写不同的JavaScript文件,然后在应用程序中组合或不组合它们,所以每个文件都需要能够恢复或构造名称空间对象,而不会破坏其他文件的工作……

一个文件可能打算使用命名空间namespace.namespace1:

namespace = window.namespace || {};
namespace.namespace1 = namespace.namespace1 || {};

namespace.namespace1.doSomeThing = function(){}

另一个文件可能想要使用命名空间namespace2:

namespace = window.namespace || {};
namespace.namespace2 = namespace.namespace2 || {};

namespace.namespace2.doSomeThing = function(){}

这两个文件可以共存,也可以分开而不会发生碰撞。

在将我的几个库移植到不同的项目中,并且不得不不断更改顶级(静态命名的)名称空间之后,我转而使用这个小的(开源的)帮助函数来定义名称空间。

global_namespace.Define('startpad.base', function(ns) {
    var Other = ns.Import('startpad.other');
    ....
});

关于好处的描述在我的博客文章中。您可以在这里获取源代码。

我非常喜欢的一个好处是模块之间相对于加载顺序的隔离。你可以在加载外部模块之前引用它。当代码可用时,将填充您获得的对象引用。

我喜欢这个:

var yourNamespace = {

    foo: function() {
    },

    bar: function() {
    }
};

...

yourNamespace.foo();