我有一个外部JavaScript文件,将在包含许多其他脚本的页面上使用。我的脚本涉及很多侦听事件的jQuery,并且通过设计,我声明了许多全局变量。我一直在阅读最佳实践文章,并且有很多关于“污染全局命名空间”和无意中的脚本交互的说法。
封装(封装?)我的JavaScript文件的最佳方法是什么,以便:
我无权透露代码,因此即使是一般回复也会受到赞赏。此外,欢迎任何其他有关使脚本不易受页面上其他脚本攻击的提示。
我发现常规JavaScript的机箱样式,但jQuery的使用是否会使这复杂化?
答案 0 :(得分:1)
一种方法是命名空间如下:
var MyNamespace = {
doSomething: function() {},
reactToEvent: function() {},
counter: 0
}
您只需使用命名空间引用函数或变量:MyNamespace.reactToEvent
。这适用于分离window
(所有对抗所在的位置)通常所具有的内容。
答案 1 :(得分:1)
您可以将代码包装在匿名Javascript函数中,并仅返回要向外界公开的内容。您需要在var
前加上全局变量,以便它们仅保留在匿名函数的范围内。像这样:
var myStuff = (function() {
var globalVar1;
var globalVar2;
var privateVar1;
function myFunction() {
...
}
function myPrivateFunction() {
...
}
return {
var1: globalVar1,
var2: globalVar2,
myFunction: myFunction
};
})();
现在,您可以访问myStuff.var1
和myStuff.myFunction()
。
答案 2 :(得分:1)
通常归结为将对象封装到“命名空间”中。我在那里使用引号,因为这个术语不是JavaScript中的官方语义,而是通过基本对象封装实现的。
有几种方法可以做到这一点,最终归结为个人偏好。
一种方法是只使用一个基本的JS对象,并保留其中的所有内容。对象的名称应该是语义的,并赋予对象一些意义,但是其他目的只是包装您自己的代码并将其保留在全局名称空间之外。
var SomeName = {
alpha: 1,
beta: {a: 1, b: 2},
gamma: function(){
SomeName.alpha += 1;
}
}
在这种情况下,只有SomeName位于全局命名空间中。这种方法的一个缺点是命名空间内的所有内容都是公共的,你必须使用完整的命名空间来引用一个对象,而不是使用“this” - 例如在SomeName.gamma中,我们必须使用SomeName.alpha来引用alpha的内容。
另一种方法是使命名空间成为具有属性的函数。这种方法的一个很好的特点是你可以通过闭包创建'private'变量。它还允许您访问已关闭的函数和变量,而无需完整的命名空间引用。
var SomeName = (function(){
var self = this;
var privateVar = 1;
var privateFunc = function() { };
this.publicVar = 2;
this.publicFunc = function(){
console.log(privateVar);
console.log(this.publicVar); // if called via SomeName.publicFunc
setTimeout(function(){
console.log(self.publicVar);
console.log(privateVar);
}, 1000);
};
}();
此方法的另一个好处是它可以保护您想要使用的全局变量。例如,如果你使用jQuery和另一个创建$变量的库,你总是可以确保在使用$时通过这种方法引用jQuery:
var SomeName = (function($){
console.log($('div'));
})(jQuery);
答案 3 :(得分:0)
封装或限制命名空间污染的两种方法
1)创建一个全局var并将所需内容填入其中。
var g = {};
g.somevar = "val";
g.someothervar = "val2";
g.method1 = function()
{
// muck with somevar
g.somevar = "something else";
};
2)对于内联脚本,请考虑限制所调用函数的范围。
<script>
(
function(window)
{
// do stuff with g.somevar
if(g.somevar=="secret base")
g.docrazystuff();
}
)(); // call function(window) then allow function(window) to be GC'd as it's out of scope now
</script>
答案 4 :(得分:0)
我刚刚开始使用RequireJS,现在已经对它着迷了。
它基本上是模块化JavaScript格式的依赖管理系统。通过这样做,您几乎可以消除将任何内容附加到全局命名空间。
唯一的好处是,您只需在页面require.js
上引用一个脚本,然后告诉它首先运行哪个脚本。从那里开始它就是魔法......
以下是一个示例实现脚本:
require([
//dependencies
'lib/jquery-1.6.1'
], function($) {
//You'll get access to jQuery locally rather than globally via $
});
阅读RequireJS API并查看这是否适合您。我现在正在写这样的所有脚本。这很棒,因为在每个脚本的顶部,您确切地知道您的依赖项与服务器端语言类似 - Java或C#。
答案 5 :(得分:0)
这是jQuery插件的常见做法,原因与您提到的相同:
;(function ($) {
/* ... your code comes here ... */
})(jQuery);
这是一个直接的功能。如果你在里面声明你的“全局”变量,它们将是这个闭包的本地变量(对于你在里面创建的代码仍然是“全局的”)。您的事件监听器也将在此处工作,您仍然可以访问真正的全局变量。