我经常看到以下代码:
(function () {
// init part
})();
但我始终无法理解它是如何工作的。我特别困惑于最后的括号。 请问有人能够用执行上下文(EC)和变量对象(VO)的术语来解释一下它是如何工作的吗?
我经常看到以下代码:
(function () {
// init part
})();
但我始终无法理解它是如何工作的。我特别困惑于最后的括号。 请问有人能够用执行上下文(EC)和变量对象(VO)的术语来解释一下它是如何工作的吗?
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*\}
呢?事实上,你可以。这就叫做匿名函数(anonymous function)。所以这两个例子也是等价的:
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
[2020年修订版]
我的之前的回答推荐了Douglas Crockford版本的括号包裹来实现这些“立即调用的匿名函数”。用户@RayLoveless在2012年建议使用现在展示的版本。当时,在ES6和箭头函数出现之前,没有明显的惯用法区别; 你只需要防止以function
关键字开头的语句。事实上,有很多方法可以做到这一点。但是使用括号,这两个语句在语法和惯用法上是等效的:
( function() { /* code */}() );
( function() { /* code */} )();
但是用户@zentechinc下面的评论提醒我,箭头函数改变了所有这些。因此现在只有其中一个语句是正确的。
( () => { /* code */ }() ); // Syntax error
( () => { /* code */ } )();
为什么这很重要?实际上,这很容易证明。记住箭头函数有两种基本形式:
() => { return 5; }; // With a function body
() => { console.log(5); };
() => 5; // Or with a single expression
() => console.log(5);
如果没有圆括号包装第二种箭头函数,你最终会得到一个惯用的混乱:
() => 5(); // How do you invoke a 5?
() => console.log(5)(); // console.log does not return a function!
这种模式将创建一个新的执行上下文(EC),其中任何本地变量对象(VO)都将存在,并且在EC退出时也将死亡。唯一的例外是成为闭包的VO。
请注意,JavaScript没有魔术的“init”函数。您可能会将此模式与此类关联,因为大多数受人尊敬的JS库(jQuery,YUI等)都会这样做,以便它们不会比需要更多地污染全局NS。
演示:
var x = 1; // global VO
(function(){
var x = 2; // local VO
})();
x == 1; // global VO, unchanged by the local VO
第二组“括号”(实际上称为圆括号或一组括号)仅是为了调用其前面定义的函数表达式(由前一组括号定义)。
这段代码创建了一个匿名函数,然后立即运行它。类似于:
var temp = function() {
// init part
}
temp();
这个结构的目的是为函数内部的代码创建一个范围。你可以在这个范围内声明变量和函数,它们将局限于该范围内。这样就不会混淆全局范围,从而最小化与其他脚本发生冲突的风险。
我简直不敢相信没有人回答运营问题!
最后一组括号用于将参数传递给匿名函数。因此,以下示例创建一个函数,然后使用x=5和y=8运行它。
(function(x,y){
//code here
})(5,8)
这可能看起来并不那么有用,但它有其存在的价值。我见过最常见的一个例子是
(function($){
//code here
})(jQuery)
这会让jQuery处于兼容模式,但你可以在匿名函数内将其称为"$"。
(function(a,b){
//Do your code here
})(1,2);
这与...相同
var test = function(x,y) {
// Do your code here
}
test(1,2);