JS中的IIFE和闭包
2019-10-08 本文已影响0人
西瓜鱼仔
IIFE( 立即调用函数表达式)
是一个在定义时就会立即执行的JavaScript函数。
(function () {
statements
})();
这是一个被称为自执行匿名函数的设计模式,主要包含两部分。第一部分是包围在 圆括号运算符
()
里的一个匿名函数,这个匿名函数拥有独立的词法作用域。这不仅避免了外界访问此 IIFE 中的变量,而且又不会污染全局作用域。
第二部分再一次使用 ()
创建了一个立即执行函数表达式,JavaScript 引擎到此将直接执行函数。
IIFE有以下特性:
1.当函数变成立即执行的函数表达式时,表达式中的变量不能从外部访问。
(function () {
var name = "Barry";
})();
// 无法从外部访问变量 name
name // 抛出错误:"Uncaught ReferenceError: aName is not defined"
2.将IIFE分配给一个变量,不是存储IIFE本身,而是存储IIFE执行后返回的结果。
var result = (function () {
var name = "Barry";
return name;
})();
// IIFE 执行后返回的结果:
result; // "Barry"
闭包
我个人理解是:因为作用域的存在,外部函数调用某个函数后,其变量对象本应该被销毁,但闭包的存在使我们仍然可以从外部访问此函数的变量对象(类比理解:比如windows系统删除正在使用的文件是删除不了的,因为文件正在被使用)。
在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
演示代码:
function show() {
var num = 666;
return function () {
console.log(num);
}
}
var show2 = show(); //show函数在此执行一次
show2();
打印结果是:666
IIFE和闭包的结合使用
1)ES5没有块作用域带来的影响
首先看一段代码:
var arr = [];
for (var i=0;i<3;i++){
arr[i] = function () {
return i;
};
}
console.log(arr[0]());
console.log(arr[1]());
console.log(arr[2]());
按照我们心理预期,结果打印应该是:0,1,2
但是最终打印结果却是:3,3,3。这是为什么呢?
我们把上述代码稍作修改:
var arr = [];
for (var i=0;i<3;i++){
arr[i] = function () {
return i;
};
}
console.log(arr[0]); //修改的地方,去掉了()
console.log(arr[1]); //修改的地方,去掉了()
console.log(arr[2]); //修改的地方,去掉了()
打印结果为:
由此可见,由于函数未实际执行,for 循环并没有把
i
的具体值给arr[]
,而是让i
待命。由于ES5没有块作用域,
for
循环条件中定义的变量 i
实际上是一个全局变量,这个 i
会随着 for
的执行,不断被覆写。直到它的值变为3,当页面加载完来执行 arr[0]()
函数时,arr[0]()
中待命的 i
会找 i
的最终结果,所以最后打印出来的是3,3,3。
2)使用IIFE+闭包解决ES5没有块作用域带来的影响。
直接上代码:
var arr = [];
for (var i=0;i<3;i++){
//使用IIFE
(function (i) {
arr[i] = function () {
return i;
};
})(i);
}
console.log(arr[0]());
console.log(arr[1]());
console.log(arr[2]());
因为IIFE是立即执行,所以 i
具体值会被写进 arr[0]()
中,最后打印结果为:0,1,2
3)附加:使用更简单的ES6语法来解决
var arr = [];
for (let i=0;i<3;i++){
//使用IIFE
(function (i) {
arr[i] = function () {
return i;
};
})(i);
}
console.log(arr[0]());
console.log(arr[1]());
console.log(arr[2]());
最后打印结果为:0,1,2.
这是因为ES6语法增加了块作用域,for
循环的值不会再随着循环执行不断覆写,而是每次循环都把 i
的值单独保存下来。