立即执行函数 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
解决办法:
- 立即执行:循环一次,执行一次
function test(){
for(var i = 0; i < 10; i++){
(function(){
console.log(i);
})();
}
}
test();
- 借助外界力量,直接传值
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
}
- 立即执行并传参
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]();
}
循环的是立即执行函数
- 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没有块级作用域,所以必须要用立即执行函数隔离全局作用域