我总是使用以下自执行功能,以避免在JavaScript中将我的代码暴露给全局范围:
(function() {
//Code comes here
})();
我相信这也称为自动执行匿名函数。有时,我也看到下面的代码用于相同的目的:
(function(d){
//Code comes here
})(document.documentElement);
我不确定这里有什么不同所以我问这个问题。
这两种类型的自执行函数在JavaScript上有什么区别(或差异)?
答案 0 :(得分:8)
下面的代码演示了正在发生的事情。实际上,foo
和bar
变量不存在,并且函数是匿名的。
var foo = function() {}
foo();
var bar = function(d){}
bar(document.documentElement);
(function(d){})(d)
方法称为闭包。它用于传递可能发生变化的变量值,例如循环。
看一个实际的例子:
for(var i=0; i<10; i++) {
document.links[i].onclick = function(){
alert(i); //Will always alert 9
}
}
实施关闭后:
for(var i=0; i<10; i++) {
(function(i){
document.links[i].onclick = function(){
alert(i); //Will alert 0, 1, ... 9
}
})(i);
}
答案 1 :(得分:3)
请记住,函数参数和变量在内心深处是相同的。
第二个例子(基本上)只是简写
(function(){
var d = document.documentElement;
}());
因为它无需var
和=
。
此模式有一些常见用途:
创建词法范围的变量(在看到Rob的答案后才记得这个......)
//this does not work because JS only has function scope.
// The i is shared so all the onclicks log N instead of the correct values
for(var i = 0; i< N; i++){
elems[i].onclick = function(){ console.log(i); }
}
//Each iteration now gets its own i variable in its own function
// so things work fine.
for(var i=0; i<N; i++){
(function(i){
elems[i].onclick = function{ console.log(i); };
}(i));
}
在这种情况下,直接传递参数允许我们以var i = i
无法使用的方式在中重复使用相同的变量名称。此外,简洁是一个好处,因为这只是一个样板模式,我们不想主导它周围的重要代码。
它可以轻松转换一些旧代码,而无需过多考虑它
(function($){
//lots of code that expected $ to be a global...
}(jQuery)) //and now we can seamlessly do $=jQuery instead.
未传递的参数设置为undefined
。这很有用,因为通常undefined
只是一个可以设置为不同值的全局变量(如果您正在编写需要使用任意第三方脚本工作的库,这一点非常重要)
(function(undefined){
//...
}())
答案 2 :(得分:0)
第一个函数不带参数。第二个采用单个参数。在函数内部,参数为d
。调用该函数时,d
设置为document.documentElement
。
答案 3 :(得分:0)
看起来第二个代码的作者想要使用d
作为在函数内编写document.documentElement
的更短方法。
答案 4 :(得分:0)
使用带有参数的第二种形式的一个原因是,使您的代码与稍后在页面上加载的其他js代码(例如其他库或框架代码)隔离,这些代码可能会重新定义作为参数传入的变量。
一个常见的例子是,如果自执行匿名函数中的代码依赖于jQuery并且想要使用$变量。
其他js框架也定义了$ variable。如果您将函数编码为:
(function($){
//Code comes here
})(jQuery);
然后你可以安全地使用$ for jQuery,即使你加载了一些定义$。的其他库。
我已经看到这个用于防守,人们在他们的块中传递他们需要的所有“全局”变量,例如窗口,文档,jQuery / $等。
比安慰更安全,特别是如果你使用了很多第三方小工具和插件。
<强>更新强>
正如其他人指出的那样,函数周围的括号集是一个闭包。在使用这种模式的情况下,很多时候它们并不是非常必要的(@Rob W给出了一个很好的例子,它们是必不可少的)但是说你有一个很长的函数体......外部括号说其他人读取代码该功能可能是自动执行的。
我看到这种模式的最佳解释是在Paul Irish的视频中:http://paulirish.com/2010/10-things-i-learned-from-the-jquery-source/从1:30左右开始
这个问题也有一些信息丰富的答案:How do you explain this structure in JavaScript?
答案 5 :(得分:0)
如果要将参数传递给自执行匿名函数,请使用第二个参数。当您想在函数中使用与全局范围内的其他名称相同的变量时,它可能会派上用场:
var a = "I'm outside the function scope",
b = 13;
alert(a);
alert(b);
(function(a,b){
// a is different from the initial a
alert(a);
// same goes for b
alert(b);
})("I'm inside the function scope",Math.PI);
使用以下内容也很有用:
var a;
console.log(a === undefined); // true
undefined = true;
console.log(a === undefined); // false
(function(undefined){
console.log(a === undefined); // true, no matter what value the variable "undefined" has assigned in the global scope
})();
尝试实施null object design pattern
时如果您担心效率,最终可能会使用以下内容:
var a = 2;
(function(window){
alert(a);
// accessing a from the global scope gets translated
// to something like window.a, which is faster in this particular case
// because we have the window object in the function scope
})(window);