我经常看到以下代码:
(function () {
// init part
})();
但我永远无法理解它是如何运作的。我发现最后一个括号特别令人困惑。 有人可以解释它在执行上下文(EC)和变量对象(VO)方面是如何工作的吗?
答案 0 :(得分:79)
我通常向人们解释的方式是展示它与其他JavaScript模式的相似之处。
首先,您应该知道有两种方法来声明一个函数(实际上,至少有五种,但这些是两个主要元凶):
function foo() {/*code*/}
和
var foo = function() {/*code*/};
即使这种结构看起来很奇怪,你也可能在附加事件时一直使用它:
window.onload=function(){/*code*/};
您应该注意到第二种形式与常规变量声明没有太大区别:
var bar = 5;
var baz = 'some string';
var foo = function() {/*code*/};
但是在JavaScript中,您总是可以选择直接使用值还是通过变量。如果bar
为5
,则接下来的两个语句是等效的:
var myVal = bar * 100; // use 'bar'
var myVal = 5 * 100; // don't use 'bar'
好吧,如果您可以单独使用5
,为什么不能单独使用function() {\*code*\}
?事实上,你可以。这就是所谓的匿名功能。所以这两个例子也是等价的:
var foo = function() {/*code*/}; // use 'foo'
foo();
(function(){/*code*/}()); // don't use 'foo'
您应该看到的唯一区别在于额外的括号。这只是因为如果你用关键字function
开始一行,解析器会认为你使用这个答案顶部的第一个模式声明一个函数并抛出一个语法错误异常。因此,将整个匿名函数包装在一对括号中,问题就会消失。
换句话说,以下三个陈述是有效的:
5; // pointless and stupid
'some string'; // pointless and stupid
(function(){/*code*/}()); // wonderfully powerful
答案 1 :(得分:48)
该模式将创建一个新的执行上下文(EC),其中任何本地变量对象(VO)将存在,并且当EC退出时同样会死亡。这一生命中唯一的例外是VO,它成为closure的一部分。
请注意,JavaScript没有神奇的“初始化”功能。您可以将此模式与此类型相关联,因为大多数任何自尊的JS库(jQuery,YUI等)都会执行此操作,以便它们不会污染全局NS,而不是他们需要的。
示范:
var x = 1; // global VO
(function(){
var x = 2; // local VO
})();
x == 1; // global VO, unchanged by the local VO
第二组“括号”(实际上称为parens或一组括号)只是调用它前面的函数表达式(由前面的括号组定义)。
答案 2 :(得分:26)
代码创建一个匿名函数,然后立即运行它。类似于:
var temp = function() {
// init part
}
temp();
这种结构的目的是为函数内部的代码创建一个范围。您可以在范围内声明变量和函数,这些变量和函数将在该范围内。这样他们就不会混淆全局范围,从而最大限度地降低与其他脚本发生冲突的风险。
答案 3 :(得分:16)
我无法相信没有人回答操作问题!
最后一组括号用于将参数传递给匿名函数。因此,以下示例创建一个函数,然后使用x = 5和y = 8
运行它(function(x,y){
//code here
})(5,8)
这似乎没那么有用,但它有它的位置。我见过的最常见的是
(function($){
//code here
})(jQuery)
允许jQuery处于兼容模式,但您可以在匿名函数中将其称为“$”。
答案 4 :(得分:7)
答案 5 :(得分:2)
简单来说你可以理解,每当页面加载时,通过这第二对方括号()函数都会调用default.We不需要调用函数。它被称为匿名函数。
即
(function(a,b){
//Do your code here
})(1,2);
和
一样var test = function(x,y) {
// Do your code here
}
test(1,2);
答案 6 :(得分:1)
它被称为immediatly调用函数表达式(IIFE)。主要与JavaScript闭包概念相关联。主要用途是在全局变量更改之前运行该函数,以便可以保留代码的预期行为。