Firefox扩展如何最好地避免污染全局命名空间?

时间:2011-07-13 09:36:47

标签: javascript firefox namespaces firefox-addon jsm

在开发Firefox扩展时,我一直在阅读有关全局命名空间污染的内容,我想在扩展中尽可能地避免使用它。有几种解决方案,但一般来说,解决方案似乎只围绕为您的扩展声明一个全局变量,并将所有内容放入其中。因此,您只需向全局命名空间添加一个额外的变量,这也不错。

简而言之,我已经向我提出了一个解决方案,它避免将任何额外变量放入全局命名空间;将所有内容包装在函数中。这里的问题是你的XUL叠加层没有任何内容可以引用。您必须在叠加层中声明元素,然后在JS中添加大量addEventListener来替换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对我来说基本上是不可接受的),为什么?

2 个答案:

答案 0 :(得分:5)

我们使用此博客文章中描述的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 :(得分:1)

你的函数必须以某种方式“活动”,所以你无法避免声称某种命名空间。我也同意你的观点,即在XUL中定义事件比附加它们更好。所以,我提出了3 + 4之间的混合:

  • 找到一个对您的插件而言唯一的名称空间,尽可能吸引人,例如“catchyseo”。
  • 将插件的所有代码和所有变量放在此命名空间中。使用匿名函数包装器模式(看看一些jQuery插件作为代码示例):

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

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