【问题标题】:How best for a Firefox extension to avoid polluting the global namespace?Firefox 扩展如何最好地避免污染全局命名空间?
【发布时间】:2011-10-04 08:23:48
【问题描述】:

在为 Firefox 开发扩展程序时,我一直在阅读有关全局命名空间污染的信息,并且我希望在我的扩展程序中尽可能避免它。有几种解决方案,但通常,这些解决方案似乎只围绕为您的扩展声明一个全局变量,并将所有内容放入其中。因此,您只需向全局命名空间添加一个额外的变量,这还不错。

顺便说一句,我已经向我提出了一个解决方案,该解决方案避免将 any 额外的变量放入全局命名空间;将所有内容包装在一个函数中。这里的问题是在您的 XUL 覆盖中没有任何可参考的内容。您必须在叠加层中声明元素,然后在 JS 中添加大量 addEventListeners 来替换 XUL 中的 oncommand="..." 之类的东西。我不想这样做;我绝对希望我的 XUL 在 XUL 本身中包含事件,因为我认为它看起来更干净,所以这不是我的解决方案。因此,我需要至少 1 个全局变量供 XUL oncommand="..." 属性引用。

因此,共识似乎是为您的扩展设置一个(也是唯一一个)变量,并将您的所有代码放入其中。这就是问题所在:通常,人们建议将该变量命名为一个漂亮的长而独特的名称,以便与其他变量发生冲突的可能性几乎为零。因此,如果我的扩展 ID 是 myextension@mycompany.com,我可以将变量命名为 myextensionAtMycompanyDotComcom.mycompany.myextension。这有利于避免全局命名空间中的冲突,但有一个问题;该变量名又长又笨重。我的 XUL 中将充斥着对事件处理程序的引用,类似于 oncommand="myextensionAtMycompanyDotCom.doSomeEvent"。没有办法避免在我的 XUL 覆盖中引用全局命名空间,因为覆盖只是被添加到浏览器窗口的 DOM 中;它没有自己的命名空间,所以我们不能以某种方式将扩展的变量范围限制在我们自己的覆盖范围内。所以,在我看来,有四种解决方案:

1。只需在 XUL 中使用长变量名

这会导致相当笨拙、冗长的 XUL 代码,例如:

<statusbarpanel id="myStatusBar" onmousedown="myextensionAtMycompanyDotCom.onMyStatusBarClick();">

2。给短变量名添加随机元素

我们为我们的扩展提供了一个更好的短变量名,比如myExt,并添加一些随机字符以使其几乎可以肯定是唯一的,例如myExtAX8T9。然后在 XUL 中,我们有:

<statusbarpanel id="myStatusBar" onmousedown="myExtAX8T9.onMyStatusBarClick();">

显然,这会导致代码相当丑陋甚至令人困惑,因为随机字符看起来很奇怪,并使它看起来像某种临时变量。

3。根本不声明任何全局变量

您可以将所有内容都封装在函数中。当然,这意味着在您的 XUL 中没有可引用的内容,因此必须在 JavaScript 代码中使用 addEventListener 将每个事件附加到 XUL 元素。我不喜欢这个解决方案,因为如上所述,我认为在 XUL 代码中引用事件更简洁,而不是必须搜索大量 JS 代码来查找哪些事件附加到哪些 XUL 元素。

4。只需在 XUL 中使用短变量名

我可以只调用我的扩展程序的变量myExt,然后我会得到很好的 XUL 代码,例如:

<statusbarpanel id="myStatusBar" onmousedown="myExt.onMyStatusBarClick();">

当然,这个短名称更有可能与全局命名空间中的其他内容发生冲突,因此并不理想。

那么,我错过了什么吗?我上面提出的 4 种解决方案有什么替代方案吗?如果不是,那 4 个中哪一个是最好的(考虑到 #3 对我来说基本上是不可接受的),为什么?

【问题讨论】:

    标签: javascript firefox namespaces firefox-addon jsm


    【解决方案1】:

    我们使用这篇博文中描述的 JavaScript 模块模式:http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth。您可以按照说明导出要在 XUL 处理程序中使用的符号。

    另外,我们使用一个颠倒的主机名作为模块名前缀,以确保我们控制命名空间:

    /* Set up the global namespace. */
    if (typeof(com) == "undefined") var com = {};
    if (!com.salsitasoft) com.salsitasoft = {};
    
    /* Main namespace. */
    com.salsitasoft.myExtensionGlobalStuffGoesHere = (function (my) {
      return my;
    })(com.salsitasoft.myExtensionGlobalStuffGoesHere || {});
    

    更新:如果它已经存在,我将其更改为将 com.salsitasoft.myExtensionGlobalStuffGoesHere 传递到闭包中,以便命名空间可以分布在多个文件中。

    【讨论】:

    • +1 为那篇博文,它非常有用。但是,您能否解释一下您的陈述,“您可以按照描述导出您想在 XUL 处理程序中使用的符号。”?当您说导出时,您实际上是在谈论使用var 在全局命名空间中声明一个变量,对吗?在您的情况下,您将其称为 com.salsitasoft.myExtensionGlobalStuffGoesHere,而 XUL 代码将始终必须引用那个长而笨重的变量名,因此它属于我的解决方案 #1 - 只需在 XUL 中使用长变量名?
    • 当我说导出时,我的意思是将其设置为“my”的属性,以便可以从函数外部访问。是的,您必须使用长名称(尽管在我的示例中您可以只使用“com.salsitasoft”,省略“myExtensionGlobalStuffGoesHere”,以使其尽可能短)。我一直支持简洁的代码(而且我的编辑器具有良好的自动完成功能),所以这不会打扰我个人。
    • 我最终以这种方式做事,并且我的扩展只有一个全局变量。我试图将我的扩展的独特性和紧凑性结合起来。在我的扩展程序中,它称为 FeatureFix,因此我将全局变量 ffixLib 命名为全局变量 ffixLib,所有内容都在其下导出,仅使用全局命名空间中的一个条目。
    【解决方案2】:

    无论哪种方式,您的函数都必须“存在”于某个地方,因此您无法避免声明某种命名空间。我也同意您的观点,即在 XUL 中定义事件比附加它们更好。所以,我提出了 3+4 的混合:

    • 为您的插件找到一个独一无二但又尽可能吸引人的命名空间,例如“catchyseo”。
    • 将插件的所有代码和所有变量都放在这个命名空间中。使用匿名函数包装模式,例如(查看一些 jQuery 插件作为代码示例):

      window.catchyseo = (function(){var private = x; [...] })();
      
    • 在您的命名空间中,公开一些您可以在 XUL 中引用的事件处理程序。

    这种方法为您提供了两全其美:您可以在 XUL 中定义您的事件,并且您有一个没有任何全局命名空间污染的封闭命名空间 - 除了您的一个命名空间变量。

    【讨论】:

    • 好吧,这并不是真正的 3 和 4 的混合体,因为 3 谈到了根本没有声明全局命名空间变量。 :-) 另外,在您的示例中,“catchyseo”代表什么?
    • "catchyseo" 是扩展的唯一名称(假设是一个虚构的 seo 工具栏插件)。 “根本没有全局命名空间变量”很难实现,在我看来在现实世界中并不可行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-14
    • 2015-03-05
    • 2014-04-25
    • 1970-01-01
    • 2020-01-03
    • 1970-01-01
    • 2016-03-10
    相关资源
    最近更新 更多