这将是一个冗长的回答,但会为您提供必要的背景知识。在JavaScript中,函数有两种定义方式:
一种是函数定义(经典类型)
function foo() {
}
并且还有更为晦涩难懂的类型,即函数表达式
var bar = function() {
};
本质上,在执行时发生了相同的事情。创建函数对象,分配内存,并将标识符绑定到函数。不同之处在于语法。前者本身是一个声明新函数的语句,后者是一个表达式。
函数表达式使我们能够在任何需要普通表达式的地方插入函数。这为匿名函数和回调函数提供了便利。例如
setTimeout(500, function() {
});
在这里,匿名函数将在setTimeout命令执行时执行。然而,如果我们想立即执行函数表达式,我们需要确保语法被识别为表达式,否则我们就会产生歧义,无法确定我们是否意味着函数表达式或语句。
var fourteen = function sumOfSquares() {
var value = 0;
for (var i = 0; i < 4; i++)
value += i * i;
return value;
}();
sumOfSquares
会立即被调用,因为它可以被识别为表达式。fourteen
变成了14
,并且sumOfSquares
被垃圾回收。在你的例子中,分组运算符()
将其内容强制转换为表达式,因此函数成为表达式,并可以立即被调用。
关于我第一个foo和bar例子之间的区别,有一件重要的事情需要注意,那就是hoisting。如果你不知道这是什么,可以快速搜索一下谷歌或其他搜索引擎来了解一下,但简单而又粗略的定义是:hoisting是JavaScript的行为,它将declarations(变量和函数)带到作用域的顶部。这些声明通常只提升标识符,而不是其初始化值,因此在赋值之前整个作用域都能看到变量/函数。
但是对于函数定义来说并非如此,这里整个声明都被提升,将在包含作用域内可见。
console.log("lose your " + function() {
fiz();
buzz();
function fiz() {
console.log("lose your scoping,");
}
var buzz = function() {
console.log("and win forever");
};
return "sanity";
}());
function() {...}
是一个声明,而(function() {...})
是一个表达式,这个表达式可以被调用,也就是说()
能够起作用。 - Niet the Dark Absol+function() { ... }()
以及!function() { ... }()
。 - Phil