IIFE (Imdiately Invoked Function Expression 立即执行的函数表达式)

函数声明

函数声明时必须有函数名

 

function fn(){};

函数表达式

函数表达式中的函数可以为匿名函数,也可以有函数名,但是该函数不能直接使用,只能通过表达式左边的变量 fn 来调用

var fn = function(){};

看看两者区别

 

function a(){
    console.log("函数声明");
}
var b = function(){
    console.log("函数表达式"); 
}
a();   //函数申明
b();   //函数表达式

 

a();   //函数声明
b();   //报错
function a(){
    console.log("函数声明");
}
var b = function(){
    console.log("函数表达式"); 
}

为什么会有这样的结果?
原因: function a(){} 为函数声明,程序运行前就已经存在;var b = function(){} 为函数表达式,属于按顺序执行,所以 b() 会报错

进入IIFE (立即执行的函数表达式)

在ES5中,是没有块级作用域的概念的;我们主要通过匿名函数的方式来块级作用域。
用作块级作用域(私有作用域)的匿名函数的语法:

(function() { //此处是块级(私有)作用域 })();

!function () { //此处是块级(私有)作用域  } ();   
~function () { //此处是块级(私有)作用域  } ();   
-function () { //此处是块级(私有)作用域  } ();   
+function () { //此处是块级(私有)作用域  } ();   

//这些都是立即执行的函数表达式的写法
//定义并立即调用了一个匿名函数。将函数声明包含在一对圆括号中,表示它实际上是一个函数表达式。
IIFE 写法的产生:
var a = function() { console.log("IIFE 写法的产生"); };
a();   //IIFE 写法的产生 
//我们将一个匿名函数赋值给了一个全局变量a,然后调用了这个函数
衍生出 IIFE 写法
(function(){
    console.log("这是一个立即执行的函数");
})();
//第一个圆括号:将匿名函数转换为函数表达式
//第二个圆括号:立即执行匿名函数(当然,你也可以设置一个函数名)

总结: 

1. 创建块级(私有)作用域,避免了向全局作用域中添加变量和函数,因此也避免了多人开发中全局变量和函数的命名冲突
2.IIFE中定义的任何变量和函数,都会在执行结束时被销毁。这种做法可以减少闭包占用的内存问题,因为没有指向匿名函数的引用。只要函数执行完毕,就可以立即销毁其作用域链

常用实例

预期: 使用 setTimeout 循环输出 0 1 2 3 4 5

for(var i = 0; i <= 5; i++){
    setTimeout(function timer(){
        console.log(i);
    },  i*1000);
}
//结果:1秒内输出6个6

原因: 超时的回调函数都将在循环完成之后立即运行。

解决方法:

方法一:
for(var i = 0; i <= 5; i++){
    (function(){
        var j = i;
        setTimeout(function timer(){
            console.log(j);
        }, j*1000)
    })();
}
//结果: 0 1 2 3 4 5
方法二:
for(var i = 0; i <= 5; i++){
    (function(j){
        setTimeout(function timer(){
            console.log(j);
        }, j*1000)
    })(i);
}
//结果: 0 1 2 3 4 5

IIFE 为每次迭代创建了新的作用域,这给了超时回调函数一个机会在每次迭代时闭包一个新的作用域。

posted @ 2017-12-29 16:44  风暴阿呆  阅读(261)  评论(0编辑  收藏  举报