在 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
中,您是否还需要全局命名空间
我明白为什么名称空间很好 - 以防止过多的全局定义并防止代码被覆盖,但我试图进一步深入研究以下语法:
// 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
相反,处理 全局对象 ,例如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
中,您是否还需要全局命名空间