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

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

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


当前回答

虽然我已经晚了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应用程序)。如果保留的话,其他文件可以重用命名空间函数(在上面包含为“可选”)。在最坏的情况下,如果这个函数被重新声明了几次——它只需要几行代码,如果简化了,就会更少。

其他回答

下面是Stoyan Stefanov在他的JavaScript Patterns一书中是如何做到这一点的,我发现这本书非常好(它还展示了他如何做注释,允许自动生成API文档,以及如何向自定义对象的原型添加一个方法):

/**
* My JavaScript application
*
* @module myapp
*/

/** @namespace Namespace for MYAPP classes and functions. */
var MYAPP = MYAPP || {};

/**
* A maths utility
* @namespace MYAPP
* @class math_stuff
*/
MYAPP.math_stuff = {

    /**
    * Sums two numbers
    *
    * @method sum
    * @param {Number} a First number
    * @param {Number} b Second number
    * @return {Number} Sum of the inputs
    */
    sum: function (a, b) {
        return a + b;
    },

    /**
    * Multiplies two numbers
    *
    * @method multi
    * @param {Number} a First number
    * @param {Number} b Second number
    * @return {Number} The inputs multiplied
    */
    multi: function (a, b) {
        return a * b;
    }
};

/**
* Constructs Person objects
* @class Person
* @constructor
* @namespace MYAPP
* @param {String} First name
* @param {String} Last name
*/
MYAPP.Person = function (first, last) {

    /**
    * First name of the Person
    * @property first_name
    * @type String
    */
    this.first_name = first;

    /**
    * Last name of the Person
    * @property last_name
    * @type String
    */
    this.last_name = last;
};

/**
* Return Person's full name
*
* @method getName
* @return {String} First name + last name
*/
MYAPP.Person.prototype.getName = function () {
    return this.first_name + ' ' + this.last_name;
};

我们可以这样单独使用它:

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

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

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

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

如果使用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”以在编写代码时保持构建的更新。

ES6 Modules命名空间导入

// circle.js
export { name, draw, reportArea, reportPerimeter };
// main.js
import * as Circle from './modules/circle.js';

// draw a circle
let circle1 = Circle.draw(myCanvas.ctx, 75, 200, 100, 'green');
Circle.reportArea(circle1.radius, reportList);
Circle.reportPerimeter(circle1.radius, reportList);

这将获取Circle .js中所有可用的导出,并使它们作为对象Circle的成员可用,有效地为其提供了自己的名称空间。

如果你需要私有作用域:

var yourNamespace = (function() {

  //Private property
  var publicScope = {};

  //Private property
  var privateProperty = "aaa"; 

  //Public property
  publicScope.publicProperty = "bbb";

  //Public method
  publicScope.publicMethod = function() {
    this.privateMethod();
  };

  //Private method
  function privateMethod() {
    console.log(this.privateProperty);
  }

  //Return only the public parts
  return publicScope;
}());

yourNamespace.publicMethod();

否则,如果你永远不会使用私有作用域:

var yourNamespace = {};

yourNamespace.publicMethod = function() {
    // Do something...
};

yourNamespace.publicMethod2 = function() {
    // Do something...
};

yourNamespace.publicMethod();