JS-立即执行函数

645 阅读2分钟

立即执行函数 IIFE (Immediately Invoked Function Expression) - 可作为初始化函数

GO里的函数不释放,随时随地都可以调用

但是立即执行函数可以自动执行,执行完成后立即释放

立即执行函数是表达式

括号包裹起来的所有东西都是表达式,或者加运算符

(1)、(function(){})、+ function test(){}()、0 || function test(){}() 、1 && function test(){}()

只有表达式才能被执行符号执行,并且表达式是会忽略名字的

形如test()、(function(){})()、var test = function(){}()

var test = function(){
    console.log(2);
}();
console.log(test); //2 undefined; 这个也是立即执行函数

2表示立即实行,打印值;执行第二次test为undefined,表示执行完就立即销毁了

下面这样是不会执行的

function test(a){
    ...
}(6);  //但是不报错

//会被分解成
function test(a){
    ...
}
(6); 

传值会被认为是表达式

不传值,变成(),会被认为是执行符号,和函数声明一起,就会报错,认为是一种语法错误,因为不是表达式

获得返回值:

声明一个变量接收返回值即可

var num = (function(a, b){
    return a + b;
}(1, 2);

经典案例

function test(){
    var arr = [];
    for(var i = 0; i < 10; i++){
        arr[i] = function(){
            console.log(i)
        }
    }
    return arr; //arr存的是10个匿名函数
}
var myArr = test();
console.log(myArr);

for(var j = 0; j < 10; j++){
    myArr[j]();  //10个10
}

解析:

function test(){
    var arr = [];
    var i = 0
    for(; i < 10; ){
        arr[i] = function(){
            console.log(i)
        }
        i++;
    }
    return arr; //arr存的是10个匿名函数
}

循环操作,将10个函数存入数组(到9依然是满足条件的,到10才不进入循环,i结束循环时是10)

因为函数不是立即执行函数,不会执行,只会以函数的形式存在于数组中

之后,return arr 形成闭包,将10个匿名函数return出去了

return出去的时候i已经变成10了

在循环arr的j项并执行的时候,拿到的值实际上是最后一次i的值,也就是10,arr里面的10个函数死死拽住test的AO

解决办法:

  1. 立即执行:循环一次,执行一次
function test(){
    for(var i = 0; i < 10;  i++){
        (function(){
            console.log(i);
        })();
    }
}
test();
  1. 借助外界力量,直接传值
function test(){
    var arr = [];
    for(var i = 0; i < 10; i++){
        arr[i] = function(num){
            console.log(num)
        }
    }
    return arr;
}
var myArr = test();
console.log(myArr);

for(var j = 0; j < 10; j++){
    myArr[j](j);  //10个10
}
  1. 立即执行并传参
function test(){
    var arr = [];
    for(var i = 0; i < 10; i++){
        (function(j){
             arr[j] = function(){
                console.log(j)
            }
        })(i);
    }
    return arr;
}
var myArr = test();
console.log(myArr);

for(var j = 0; j < 10; j++){
    myArr[j]();
}

循环的是立即执行函数

  1. let
function test(){
    var arr = [];
    for(let i = 0; i < 10; i++){
        arr[i] = function(){
            console.log(i)
        }
    }
    return arr; //arr存的是10个匿名函数
}

应用场景:

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
</ul>
var oLi = document.querySelectorAll('li');
for(var i = 0; i < oLi.length; i++){
    oLi[i].onclick = function(){
        console.log[i];  //打印出来都是5
    }
}

解决方法:

for(var i = 0; i < oLi.length; i++){
    (function(j){
        oLi[j].onclick = function(){
            console.log[j];
        }
    })(i);
}

插件开发

return 和 window 都可以东西甩到全局里

function test(){
    var a = 1;
    function add(){
        a++;
        console.log(a);
    }
    window.add = add;
}
test();
add(); //2
add(); //3
add(); //4

自启动函数

var add = (function(){
    var a = 1;
    function add(){
        a++;
        console.log(a);
    }
    return add; //需要一个变量接收return值
})();
add(); //2
add(); //3
add(); //4
(function(){
    var a = 1;
    function add(){
        a++;
        console.log(a);
    }
    window.add = add; //用window就不需要一个变量接收return值,直接存到window里
})();
add(); //2
add(); //3
add(); //4

JS插件写法

;(function(){
    function Test(){
        //...
    }
    Test.prototype = {
        init: function(){
            this.bindEvent();
        },
        bindEvent: function(){},
        ...
    }
    window.Test = Test;
})();
var test = new Test().init();

这样就不会污染全局作用域

加';'是为了防止忘了在后面加

因为ES5没有块级作用域,所以必须要用立即执行函数隔离全局作用域