前面的闭包中,提到与闭包类似的当即执行函数,感受二者仍是比较容易弄混吧,严格来讲(由于犀牛书和高程对闭包的定义不一样),当即执行函数并不属于闭包,它不知足闭包的三个条件。javascript
圆括号运算符也叫分组运算符,它有两种用法:若是表达式放在圆括号中,做用是求值;若是跟在函数后面,做用是调用函数java
把表达式放在圆括号之中,将返回表达式的值闭包
console.log((1+2)); // 3
将函数放在圆括号中,会返回函数自己。若是圆括号紧跟在函数的后面,就表示调用函数,即对函数求值模块化
console.log((function testa(){return 666;})); // function testa(){return 666;} console.log(function testa(){return 666;}()); // 666
注意:圆括号运算符不能为空,不然会报错函数
();//SyntaxError: Unexpected token )
因为圆括号的做用是求值,若是将语句放在圆括号之中,就会报错,由于语句没有返回值code
(var a = function(){return 666}); // SyntaxError: Unexpected token var
使用 function
关键字建立一个函数,而且后面带有函数名,叫函数声明。token
function testa(){}
那么使用 function
关键字建立的函数不带函数名呢? 那就是匿名函数了。ip
function (){}
那么把匿名函数赋值给一个变量呢?那就是函数表达式了。作用域
var testa = function (){}
其实呢,函数表达式的根本所在,就是阻止了js引擎把 用function
建立的函数 看成函数声明来解析。下面再详说。io
那么当即执行函数呢?
用function
定义函数以后,当即调用该函数。这种函数就叫作当即执行函数,全称为当即调用的函数表达式IIFE(Imdiately Invoked Function Expression)
一、在本系列进击的 JavaScript(三)中到过,代码执行时,会先对函数声明的函数 进行解析(函数声明提高),而函数表达式,当逐行执行到它时,才会解析。
二、正由于函数声明的提高,致使函数声明不能当即执行。由于,函数声明时,js只会解析到大括号(})就结束了,若是后面有()
,只是一个圆括号运算符。
function testa(){ console.log("testa") }("666") //"666" //若是后面是一个空的圆括号,会报错,上面提到过。
因此,不知道,你有没有发现,函数声明的函数,后面能够不用分号(;)分隔,也能够正常执行,而函数表达式的后面就必须加分号,否则会报错。你能够本身写个小栗子验证下。
三、匿名函数是不能单独写的,因此就提不上当即执行了。
function (){} //Uncaught SyntaxError: Unexpected token (
单独写匿名函数,是会报错的,js引擎 会把它看成函数声明来解析,而函数声明就必需要有个函数名,因此会报错。
因此,你一般看到使用匿名函数,都是看成参数传递的,或者把匿名函数转为函数表达式。
四、所以,只有函数表达式能够当即执行
var testa = function (){ console.log("testa") }() //"testa"
上面提到过,函数表达式,就是阻止了js引擎把 |用function
建立的函数| 看成函数声明来解析。
注:javascript引擎规定,若是function关键字出如今行首,一概解释成函数声明语句。
因此,解决方法就是不要让function出如今行首,让引擎将其理解成一个表达式。
//经常使用的两种,使用圆括号运算符 (function(){console.log("666")})() (function(){console.log("666")}()) //一元运算符写法 !function(){console.log("666")}() +function(){console.log("666")}() -function(){console.log("666")}() ~function(){console.log("666")}()
都是均可以把函数声明 转为 函数表达式,也就是阻止了把其看成函数声明解析。
一、当即执行函数能配合闭包保存状态。
来看下 上节内容中闭包的例子:
function makeClosures(i){ var i = i; return function(){ console.log(i); } } for (var i=1; i<=5; i++) { setTimeout(makeClosures(i),i*1000); } //1 //2 //3 //4 //5
如今,咱们来利用当即执行函数来简化它:
for (var i=1; i<=5; i++) { setTimeout((function(i){ return function(){ console.log(i); } })(i),i*1000); }
第一个匿名函数执行完毕后,返回了第二个匿名函数。第二个匿名函数被当作setTimeout 的第一个参数传入进去。由于 setTimeout函数执行了5次,因此当即执行函数里每次都会返回了一个没有被执行的匿名函数,(这里就是返回了5个匿名函数),每一个匿名函数内部保存着每次传进来的i值,所以,每一个i 都是不同的,因此,就获得了想要的结果
二、当即执行函数配合闭包 模块化中应用
(function(){ var meg = "hello zdx"; function say(arg){ arg = arg || meg; console.log(arg) } window.say = say; })(window) window.say(); //"hello zdx"
首先当即执行函数,它是个匿名函数,你是得不到它的函数引用,这样,就避免了全局变量污染。其次,因为函数做用域的规则,在匿名函数外部是访问不了函数内的变量,函数等的。因此,也常常用当即执行函数模拟块级做用域。