【问题标题】:Safely creating namespaces in JavaScript在 JavaScript 中安全地创建命名空间
【发布时间】:2015-07-10 11:21:55
【问题描述】:

我理解为什么命名空间是好的 - 以防止过多的全局定义并防止代码被覆盖,但我正在尝试进一步挖掘以下语法:

// 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,会发生什么?代码不会初始化变量并且没有创建命名空间?这是否意味着您的代码将永远无法工作?如果是,那又是什么呢?

【问题讨论】:

  • 如果MYAPPLICATION 变量已经启动,它将使用已经启动的变量:MYAPPLICATION = MYAPPLICATION。如果没有启动,它将创建一个新对象:|| {};
  • 那么,如果它使用的是别人创建的预先存在的,你的代码是不是有可能发生冲突?如果其他人定义了函数 foo(){return "bar"} 而我的代码定义了相同的函数 foo(){return "hello world"} 调用函数 foo() 时会发生什么?
  • @sjmartin 是的,事情有可能发生冲突。这就是为什么你应该使用一个相当独特的命名空间,而不用太担心它。
  • 在那种情况下你可能会得到一个 TypeError 。您的命名空间应该是唯一的。你所有的函数和对象都应该属于那个命名空间。这限制了与其他库发生冲突的可能性。
  • 这就是 require.js 存在的原因:避免污染全局命名空间并以合理的方式管理冲突。

标签: javascript namespaces


【解决方案1】:

会发生什么情况是您的应用程序将覆盖前一个应用程序的属性,反之亦然,具体取决于首先执行的应用程序。

在 javascript 中“几乎”所有内容都可以被覆盖。您的应用程序只是全局范围内的一个简单对象,因此如果其他应用程序是这样编写的。

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 这样的长名称解析。

【讨论】:

    【解决方案2】:

    您的第二个示例不会像您期望的那样工作; 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

    中,你是否甚至需要全局命名空间

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-29
      相关资源
      最近更新 更多