在 JavaScript 中安全地创建命名空间

Safely creating namespaces in JavaScript

我明白为什么名称空间很好 - 以防止过多的全局定义并防止代码被覆盖,但我试图进一步深入研究以下语法:

// not safe, if there's another object with this name we will overwrite it
var MYAPPLICATION = {};

// We need to do a check before we create the namespace
if (typeof MYAPPLICATION === "undefined") {
    var MYAPPLICATION = {};
}

// or a shorter version
var MAYAPPLICATION = MYAPPLICATION || {};

好的,第一行代码不安全,因为 MYAPPLICATION 可以在其他地方或由不同的库定义。

第二行检查它是否存在,如果不存在则用新对象定义 var MYAPPLICATION。

我的问题是,如果预先定义了 MYAPPLICATION 会发生什么?代码不会初始化变量并且不会创建名称空间?这是否意味着您的代码将永远无法工作?如果是,那又怎样?

您的应用程序将覆盖前一个应用程序的属性,反之亦然,具体取决于哪个先执行。

在javascript "almost"中,一切都可以被覆盖。你的应用程序只是一个全局范围内的简单对象,所以如果其他应用程序是这样写的。

var MYAPPLICATION = {};
MYAPPLICATION.foo = function () {....}

而你的是

var MYAPPLICATION = MYAPPLICATION || {};
MYAPPLICATION.bar = function () {...}

您最终会得到一个名为 MYAPPLICATION 的全局变量,它具有两个属性 'foo' 和 'bar',并在其上定义了函数。

一个是你的,另一个不是你的,所以你的代码可能会出现意外行为。所以换句话说,在 javascript 中没有真正安全的方法来创建命名空间。

您可以查看这篇 SO 文章 Is there a "concise" way to do namespacing in JavaScript? 了解更多信息,但我个人建议您改用 沙盒模式 。这将帮助您更好地隔离代码。

这是 post 包含一个帮助您入门的示例。这解决了命名空间模式的一些问题,例如同一应用程序的多个版本和长名称解析,如 app.module.foo.bar.daa。

你的第二个例子不会像你期望的那样工作; var 将被提升。 ES5 允许多次尝试 var 相同的标识符(参见 spec §10.5, 8. c.

在严格模式下,如果你简单地删除 var

,你可能会得到一个 ReferenceError

相反,处理 全局对象 ,例如window

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

或者如果您不想假设它是真实的,您可以检查是否存在 属性

if (!(my_namespace in window)) {
    window.my_namespace = {};
}

您可以通过编写 IIFEs

进一步保持命名空间的清洁
if (!window.my_namespace) {
    window.my_namespace = (function () {
        var o = {}, a = 'foo', b = 'bar';
        o[a] = b;
        return o; // pass out reference
    }()); // {foo: "bar"}
}

或者考虑一下,如果您将所有内容都保存在 IIFE

中,您是否还需要全局命名空间