这将是一个冗长的答案,但会为您提供必要的背景知识。在 JavaScript 中有两种方法可以定义函数: 函数定义(经典类型)
function foo() {
//why do we always use
}
然后是更晦涩的类型,一个函数表达式
var bar = function() {
//foo and bar
};
本质上,同样的事情在执行时正在发生。创建一个函数对象,分配内存,并为该函数绑定一个标识符。区别在于语法。前者本身就是一个声明新函数的语句,后者是一个表达式。
函数表达式使我们能够在任何需要正常表达式的地方插入函数。这有助于匿名函数和回调。以
setTimeout(500, function() {
//for examples
});
在这里,只要 setTimeout 如此声明,匿名函数就会执行。但是,如果我们想立即执行函数表达式,则需要确保语法可识别为表达式,否则我们会不确定我们是指函数表达式还是语句。
var fourteen = function sumOfSquares() {
var value = 0;
for (var i = 0; i < 4; i++)
value += i * i;
return value;
}();
HeresumOfSquares
被立即调用,因为它可以被识别为一个表达式。fourteen
变成14
并且 sumOfSquares 被垃圾收集。在您的示例中,分组运算符将()
其内容强制转换为表达式,因此该函数是一个表达式,因此可以立即调用。
关于我的第一个 foo 和 bar 示例之间的区别,需要注意的一件重要事情是提升。如果你不知道它是什么,一两次快速的谷歌搜索应该会告诉你,但快速而肮脏的定义是提升是 JavaScript 将声明(变量和函数)带到作用域顶部的行为。这些声明通常只提升标识符而不是它的初始化值,因此整个范围将能够在分配值之前看到变量/函数。
对于函数定义,情况并非如此,这里整个声明都被提升并且在整个包含范围内都是可见的。
console.log("lose your " + function() {
fiz(); //will execute fiz
buzz(); //throws TypeError
function fiz() {
console.log("lose your scoping,");
}
var buzz = function() {
console.log("and win forever");
};
return "sanity";
}()); //prints "lose your scoping, lose your sanity"