在开发 Firefox 扩展时,我一直在阅读有关全局名称空间污染的信息,并且我希望在我的扩展中尽可能避免这种情况。有多种解决方案,但一般来说,这些解决方案似乎只为您的扩展声明一个全局变量,并将所有内容放入其中。因此,您只需向全局命名空间添加一个额外的变量,这还算不错。
顺便说一句,我提出了一个解决方案,可以避免将任何额外变量放入全局命名空间中;将所有内容包装在一个函数中。这里的问题是 XUL 覆盖中没有任何内容可供参考。您必须在叠加层中声明元素,然后在 JS 中添加大量 addEventListener
来替换类似于 oncommand="..."
的内容在XUL。我不想这样做;我绝对希望我的 XUL 在 XUL 本身中包含事件,因为我认为它看起来更干净,所以这对我来说不是一个解决方案。因此,我至少需要 1 个全局变量供 XUL oncommand="..."
属性引用。
因此,共识似乎是为您的扩展提供一个(且只有一个)变量,并将所有代码放入其中。问题是:通常,人们建议将该变量命名为一个漂亮的长且唯一的名称,以便与其他变量发生冲突的机会几乎为零。因此,如果我的扩展程序 ID 为 [电子邮件受保护]
,我可以将我的变量命名为 myextensionAtMycompanyDotCom
或 com.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 对我来说基本上是不可接受的),为什么?
I've been reading up on global namespace pollution when developing an extension for Firefox, and I want to avoid it as much as possible in my extension. There are several solutions, but generally, the solutions seem to center around only declaring one global variable for your extension, and putting everything in that. Thus you only add one extra variable to the global namespace, which isn't too bad.
As a brief aside, I have had a solution proposed to me that avoids putting any extra variables into the global namespace; wrap everything in a function. The problem here is that there's nothing to refer to in your XUL overlays. You have to declare elements in your overlays, and then in JS add a ton of addEventListener
s to replace what would've been something like an oncommand="..."
in XUL. I don't want to do this; I definitely want my XUL to include events in the XUL itself because I think it looks cleaner, so this isn't a solution for me. I therefore need at least 1 global variable for XUL oncommand="..."
attributes to refer to.
So the consensus seems to be to have one (and only one) variable for your extension, and put all your code inside that. Here's the problem: generally, people recommend that that variable be named a nice long, unique name so as to have almost zero chance of colliding with other variables. So if my extension's ID is [email protected]
, I could name my variable myextensionAtMycompanyDotCom
, or com.mycompany.myextension
. This is good for avoiding collisions in the global namespace, but there's one problem; that variable name is long and unwieldy. My XUL is going to be littered with references to event handlers along the lines of oncommand="myextensionAtMycompanyDotCom.doSomeEvent"
. There's no way to avoid having to refer to the global namespace in my XUL overlays, because an overlay just gets added to the browser window's DOM; it doesn't have a namespace of its own, so we can't somehow limit our extension's variable scope only to our own overlays. So, as I see it, there are four solutions:
1. Just use the long variable name in XUL
This results in rather unwieldy, verbose XUL code like:
<statusbarpanel id="myStatusBar" onmousedown="myextensionAtMycompanyDotCom.onMyStatusBarClick();">
2. Add an element of randomness to a short variable name
We come up with a much nicer short variable name for our extension, let's say myExt
, and add some random characters on to make it almost certainly unique, such as myExtAX8T9
. Then in the XUL, we have:
<statusbarpanel id="myStatusBar" onmousedown="myExtAX8T9.onMyStatusBarClick();">
Clearly, this results in rather ugly and even confusing code as the random characters look odd, and make it look like some kind of temporary variable.
3. Don't declare any global variables at all
You could just wrap up everything in functions. This, of course, means that there is nothing to refer to in your XUL, and so every event must be attached to the XUL elements using addEventListener
in your JavaScript code. I don't like this solution because, as mentioned above, I think it's cleaner to have the events referenced in the XUL code rather than having to search a ton of JS code to find which events are attached to which XUL elements.
4. Just use a short variable name in XUL
I could just call my extension's variable myExt
, and then I get nice XUL code like:
<statusbarpanel id="myStatusBar" onmousedown="myExt.onMyStatusBarClick();">
Of course, this short name is much more likely to clash with something else in the global namespace and so isn't ideal.
So, have I missed something? Is there any alternative to the 4 solutions I proposed above? If not, what would be the best of the 4 (given that #3 is basically unacceptable to me), and why?
发布评论
评论(2)
我们使用这篇博文中描述的 JavaScript 模块模式: http:// /www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth。您可以按照所述导出要在 XUL 处理程序中使用的符号。
此外,我们使用反向主机名作为模块名称前缀,以确保我们控制命名空间:
更新:我更改了此设置,将 com.salsitasoft.myExtensionGlobalStuffGoesHere 传递到闭包中(如果它已经存在),以便命名空间可以分布在多个文件。
We use the JavaScript module pattern described in this blog post: http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth. You can export the symbols that you want to use in your XUL handlers as described.
In addition, we use a reversed host name as the module name prefix to ensure that we control the namespace:
Update: I changed this to pass com.salsitasoft.myExtensionGlobalStuffGoesHere into the closure if it already exists so that the namespace can be spread across multiple files.
无论哪种方式,你的函数都必须“存在”在某个地方,因此你无法避免声明某种名称空间。我也同意你的观点,即在 XUL 中定义事件比附加它们更好。因此,我建议采用 3+4 的混合:
将插件的所有代码和所有变量放入此命名空间中。使用匿名函数包装器模式,例如(查看一些 jQuery 插件作为代码示例):
在您的命名空间中,公开一些您可以在 XUL 中引用的事件处理程序。
这种方法为您提供了两个世界中最好的:您可以在 XUL 中定义事件,并且您拥有一个封闭的名称空间,没有任何全局名称空间污染 - 除了您的一个名称空间变量。
Your functions have to "live" somewhere either way, so you cannot avoid to claim some kind of namespace. I also agree to your point that defining the event in the XUL is better than attaching them. So, I propose a hybrid between 3+4:
Place all the code of your plugin and all variables inside this namespace. Use the anonymous function wrapper pattern like (have a look at some jQuery plugins as code examples):
In your namespace, expose some event handlers which you can reference in your XUL.
This approach gives you the best of two worlds: you can define your events in XUL and you have a closed namespace without any global namespace pollution - except your one namespace variable.