我们定义一个函数,一般有两种方法
- 函数声明
function fnName(){...};
- 函数表达式
var fn = function fnName(){...}
声明函数后,我们可以使用fnName ()来调用这个函数
function f1(){
console.log('函数声明')
}
f1()
//输出:函数声明。
var f1 = function f2(){
console.log('函数声明')
}
f1()
//输出:函数表达式。
那么我们可不可以直接在后面加()直接调用这个函数呢?
function f1(){
console.log('函数声明')
}()
// 报错 SyntaxError: Unexpected token (
var f1 = function f2(){
console.log('函数声明')
}()
//输出 函数声明
为什么会这样呢,原来,JavaScript解释器会在默认的情况下把遇到的function关键字当作是函数声明语句(statement)来进行解释的,所以第一种写法是有语法错误的。
这时我们可以总结出两种函数声明方式的不同
- Javascript引擎在解析javascript代码时会'函数声明提升'(Function declaration Hoisting)当前执行环境(作用域)上的函数声明,而函数表达式必须等到Javascirtp引擎执行到它所在行时,才会从上而下一行一行地解析函数表达式。
- 函数表达式后面可以加括号立即调用该函数,函数声明不可以,只能以fnName()形式调用 。
所以,要在函数体后面加括号就能立即调用,则这个函数必须是函数表达式,不能是函数声明。
一个匿名函数想立即执行就需要把它变成一个表达式,这就是立即执行函数表达式。
(function(){alert('我是匿名函数')} ()) // 用括号把整个表达式包起来
(function(){alert('我是匿名函数')}) () //用括号把函数包起来
所以根据上面的解释,我们知道只要能让JavaScript引擎以「函数表达式」而不是「函数声明」来处理匿名函数的立即执行就可以了,把语句放在()之中只是其中的一种方法而已,根据这个思路我们可以用其他方式来实现同样的目的,比如:
!function(){alert('我是匿名函数')}() // 求反,我们不在意值是多少,只想通过语法检查。
+function(){alert('我是匿名函数')}()
-function(){alert('我是匿名函数')}()
~function(){alert('我是匿名函数')}()
void function(){alert('我是匿名函数')}()
new function(){alert('我是匿名函数')}()
立即执行函数表达式有什么作用呢?
只有一个作用:创建一个独立的作用域。
这个作用域里面的变量,外面访问不到(即避免「变量污染」)。