Javascript Firefox扩展如何避免污染全局名称空间?

Javascript Firefox扩展如何避免污染全局名称空间?,javascript,firefox,namespaces,firefox-addon,jsm,Javascript,Firefox,Namespaces,Firefox Addon,Jsm,在为Firefox开发扩展时,我一直在阅读有关全局名称空间污染的内容,我希望在扩展中尽可能避免它。有几种解决方案,但通常情况下,解决方案似乎只围绕为扩展声明一个全局变量,并将所有内容都放在其中。因此,您只需向全局名称空间添加一个额外变量,这并不太糟糕 简单地说,我已经向我提出了一个解决方案,避免将任何额外的变量放入全局名称空间;将所有内容封装在函数中。这里的问题是,在XUL覆盖中没有任何内容可供参考。您必须在覆盖中声明元素,然后在JS中添加大量的addEventListeners来替换XUL中类

在为Firefox开发扩展时,我一直在阅读有关全局名称空间污染的内容,我希望在扩展中尽可能避免它。有几种解决方案,但通常情况下,解决方案似乎只围绕为扩展声明一个全局变量,并将所有内容都放在其中。因此,您只需向全局名称空间添加一个额外变量,这并不太糟糕

简单地说,我已经向我提出了一个解决方案,避免将任何额外的变量放入全局名称空间;将所有内容封装在函数中。这里的问题是,在XUL覆盖中没有任何内容可供参考。您必须在覆盖中声明元素,然后在JS中添加大量的
addEventListener
s来替换XUL中类似于
oncommand=“…”
的内容。我不想这样做;我确实希望我的XUL在XUL中包含事件,因为我认为它看起来更干净,所以这不是我的解决方案。因此,我需要至少1个全局变量来引用XUL
oncommand=“…”
属性

因此,大家的共识似乎是为扩展提供一个(而且只有一个)变量,并将所有代码放在其中。问题是:一般来说,人们建议将该变量命名为一个很长、唯一的名称,这样就几乎没有机会与其他变量发生冲突。所以如果我的扩展ID是
myextension@mycompany.com
,我可以将变量命名为
myextensionAtMycompanyDotCom
,或
com.mycompany.myextension
。这有助于避免全局名称空间中的冲突,但有一个问题;这个变量名很长而且很难处理。我的XUL将充斥着对事件处理程序的引用,这些引用的行是
oncommand=“myextensionAtMycompanyDotCom.doSomeEvent”
。没有办法避免在我的XUL覆盖中引用全局名称空间,因为覆盖只是被添加到浏览器窗口的DOM中;它没有自己的名称空间,所以我们不能将扩展的变量范围限制在我们自己的覆盖上。因此,在我看来,有四种解决方案:

1.只需在XUL中使用长变量名 这会导致相当笨拙、冗长的XUL代码,如:

<statusbarpanel id="myStatusBar" onmousedown="myextensionAtMycompanyDotCom.onMyStatusBarClick();">
<statusbarpanel id="myStatusBar" onmousedown="myExt.onMyStatusBarClick();">
显然,这会导致相当难看甚至混乱的代码,因为随机字符看起来很奇怪,使它看起来像某种临时变量

3.根本不声明任何全局变量 您可以将所有内容都封装在函数中。当然,这意味着您的XUL中没有可引用的内容,因此必须使用JavaScript代码中的
addEventListener
将每个事件附加到XUL元素。我不喜欢这个解决方案,因为如上所述,我认为在XUL代码中引用事件比搜索大量JS代码来查找哪些事件附加到哪些XUL元素更干净

4.只需在XUL中使用一个简短的变量名 我可以直接调用扩展名的变量
myExt
,然后得到很好的XUL代码,如:

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

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

那么,我错过了什么吗?除了我上面提出的4种解决方案,还有其他选择吗?如果不是,那么4个函数中最好的是什么(考虑到#3对我来说基本上是不可接受的),为什么?

您的函数必须以任何方式“存在”在某个地方,因此您不能避免声明某种名称空间。我也同意你的观点,在XUL中定义事件比附加事件更好。因此,我建议在3+4之间进行混合:

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

  • 在命名空间中,公开一些可以在XUL中引用的事件处理程序


这种方法提供了两个世界中最好的一个:你可以在XUL中定义你的事件,你有一个封闭的名称空间,除了你的一个名称空间变量之外,没有任何全局名称空间污染。可以导出要在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.myExtensionGlobalStuffGoesher传递到闭包中(如果它已经存在),以便名称空间可以分布在多个文件中。

这并不是3和4之间的混合,因为3表示根本不声明全局名称空间变量。:-)另外,在您的示例中,“catchyseo”代表什么?“catchyseo”是扩展的唯一名称(假设是一个虚构的seo工具栏插件)。“根本没有全局名称空间变量”是很难实现的,在我看来,在现实世界中并不可行。+1对于那篇博文,它非常有用。但是,您能否解释一下您的陈述,“您可以导出您希望在XUL处理程序中使用的符号,如前所述。”?当您说导出时,实际上是在使用
var
在全局命名空间中声明一个变量,对吗?在您的例子中,您将其命名为
com.salsitasoft.myExtensionsGlobalStuffGoesher
,XUL代码将始终引用那个冗长而笨拙的变量名,因此它将属于我的解决方案#1-只需在XUL中使用长变量名?当我说导出时,我的意思是将其设置为“my”的属性这样就可以从函数外部访问。是的,您必须使用长名称(尽管在我的示例中您可以只使用“com.salsitasoft”,而不使用“myExten”)