介绍
IIFE(Immediately Invoked Function Expression),即立即执行函数表达式,也称为自执行匿名函数;特点时定义即执行;
参考下面的demo,我们可以看到IIFE由两个部分组成:
- 第一部分由词法作用域被分组操作符
()
包裹的匿名函数组成;这可以防止访问IIFE惯用语中的变量及污染全局作用域;- 第二部分通过
()
创建立即执行表达式;所以JS引擎可以直接执行它;
(function foo() {
console.log(1);
})()
应用
通过创建闭包避免一些错误
// 常见demo: 期望输出1-5,实际输出5个6;
for (var i=1; i<=5; i++) {
setTimeout(function () {
console.log(i)
}, i*1000)
}
// 使用立即执行函数,将i作为外部参数传入立即执行函数
for (var i=1; i<=5; i++) {
(function (j) {
setTimeout(function () {
console.log(j);
}, j*1000)
})(i)
}
拓展
对于非匿名的立即执行函数,其在执行时在函数执行上下文中会为其分配一个与函数名同名的只读属性,用于指向该函数;该属性有一个name子属性,值为函数名,可以在IIFE内部访问到函数名;
但是EC的执行包括进入(初始化)和执行;在函数作用域(FC)中,在进入阶段,活动对象(AO)会由形参初始化并进行函数声明(同名覆盖)和变量声明(这也是变量提升和函数提升的原因);执行阶段按照执行顺序再去赋值;
所以可以看到,在我们在非匿名立即函数中未声明与函数名同名的变量时,我们可以访问到foo及foo.name;一旦我们声明了同名变量,那么在AO初始化阶段就会被覆盖,导致foo.name无法访问;
总结:非匿名的IIFE中,内部默认存在一个与函数名同名的一个只读属性,如果函数内部不重新声明变量或函数,则该值不会被修改(截图第二个例子);否则会被重新声明;(截图第一/三例子);这与在普通函数中的表现存在一些差异:
function foo() {
console.log('name: ', foo.name); // name: foo
foo = 1;
console.log(foo); // 1
}
(function foo() {
console.log('name: ', foo.name); // name: foo
foo = 1;
console.log('foo: ', foo.name); // foo: foo
})()