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

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

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


当前回答

下面是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;
};

其他回答

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

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

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

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

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

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

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

我通常在闭包中构建它:

var MYNS = MYNS || {};

MYNS.subns = (function() {

    function privateMethod() {
        // Do private stuff, or build internal.
        return "Message";
    }

    return {
        someProperty: 'prop value',
        publicMethod: function() {
            return privateMethod() + " stuff";
        }
    };
})();

自从写了这篇文章以来,我的风格在这些年里有了微妙的变化,现在我发现自己是这样写闭包的:

var MYNS = MYNS || {};

MYNS.subns = (function() {
    var internalState = "Message";

    var privateMethod = function() {
        // Do private stuff, or build internal.
        return internalState;
    };
    var publicMethod = function() {
        return privateMethod() + " stuff";
    };

    return {
        someProperty: 'prop value',
        publicMethod: publicMethod
    };
})();

通过这种方式,我发现公共API和实现更容易理解。将return语句视为实现的公共接口。

我的习惯是使用函数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();其他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();

JavaScript:使用Object.create()创建对象