IIFE: Immediately Invoked Function Expression,翻译过来就是当即调用的函数表达式。也就是说,在函数声明的同时当即调用这个函数。javascript
普通的函数声明和函数调用java
function bar() { var a = 10; console.log(a); } bar(); // 函数调用 复制代码
IIFE函数声明和调用bash
(function foo(){ var a = 10; console.log(a); })(); 复制代码
首先注意一点的就是IIFE函数是由一对()将函数声明包裹起来的表达式。使得JS编译器再也不认为这是一个函数声明,而是一个IIFE,即马上执行函数表达式。 可是二者达到的目的都是同样的,都是声明了一个函数而且随后调用这个函数。微信
若是只是为了当即执行一个函数,显然IIFE所带来的好处有限。实际上,IIFE的出现是为了弥补JS在scope方面的缺陷:JS只有全局做用域(global scope)、函数做用域(function scope),从ES6开始才有块级做用域(block scope)。对比如今流行的其余面向对象的语言能够看出,JS在访问控制这方面是多么的脆弱!那么如何实现做用域的隔离呢?在JS中,只有function才能实现做用域隔离,所以若是要将一段代码中的变量、函数等的定义隔离出来,只能将这段代码封装到一个函数中。markdown
为调用一次的函数达到做用域隔离、命名冲突、减小内存占用问题。闭包
在ES5中是没有块级做用域的概念。只有全局做用域和函数做用域函数
for (var i = 0; i< 10; i++) { console.log(i); } console.log(i); // 10 复制代码
这个地方能够看出for循环中的变量i是一个全局变量,在for循环执行完毕后这个i仍是能够访问到的。i并无被销毁spa
块级做用域也能够称为私有做用域。也就是说只在for循环的语句块中有定义,一旦循环结束,变量i就会被销毁,而在ES5中咱们主要使用匿名函数【IIFE】的方式来达到块级做用域的效果。翻译
// 函数声明语句写法 function test() {}; test(); // 函数表达式写法 var test = function(){}; test(); 复制代码
[注意]javascript引擎规定,若是function关键字出如今行首,一概解释成函数声明语句;而函数声明后面是不能跟圆括号的(匿名函数是函数声明的一种)。然而,函数表达式的后面能够跟圆括号。因此能够将函数声明转换成函数表达式。 在当即执行函数中,定义的变量会在当即code
因此,解决方法就是不要让function出如今行首,让引擎将其理解成一个表达式 最经常使用的几种办法
(function(){ console.log('123'); }()); (function(){ console.log('123'); })(); (function foo(){ console.log('123'); })(); 复制代码
对于当即执行函数末尾的;分号,最好加上,由于若是不加,遇到两个都是用括号()包裹执行的IIFE时,就会遇到问题。
(function(){ console.log('a'); })() (function(){ console.log('b'); })() 复制代码
这一段代码只有a能够显示出来,b会报错
TypeError: (intermediate value)(...) is not a function
不加分号,上面的内容会被JS理解为:
(function(){ console.log('a'); })()(function(){ console.log('b'); })() 复制代码
也就是说,a匿名函数执行后,没有;的隔断,后面的b当即执行函数与a合成了一个函数。执行到输出完a时,没有reutrn,后面的()至关于对undefined进行了执行,因此报错。
咱们能够这样修改
(function(){ console.log('a'); })() (function(){ console.log('b'); }()) 复制代码
这样修改后,a,b都会显示出来,可是一样会报错, 还有其余的修改方式,可是我建议加上;分号避免报错。
欢迎关注微信公众号