立即执行函数(IIFE)
立即执行函数,也叫IIFE,immediately invoked function expression立即调用函数表达式。这个函数在被定义好那一刻已经被执行了。 这个函数执行完之后直接销毁,不留痕迹
立即执行函数写法
一个括号把匿名函数放进去,然后后面带上一个括号表示执行。
// 第一种形式
(function () {}())
// 第二种形式
(function ())()
例子
现在有一个要求,要求在循环内输出0到9。但肯定不会这么简单,在这基础上,要求是要在3秒后输出。 这时候就有人会想那多简单啊,就写出了下面的代码
for(var i = 0; i < 10; i ++) {
setTimeout(function () {
console.log(i);
}, 3000)
}
但数输出结果却不尽人意,结果是10个10。那为什么会这样呢。 原因是这样的
- 循环里面定义了一个定时器,在3秒钟之后执行。
- 声明了一个变量i,这个i是在全局上定义的。
- 每一次循环的时候,都会创建一个定时器,然后 i ++。这个时候定时器。
- 当i加到10的时候,i < 10为false,不会进入循环,这个时候已经创建了10个定数器了,这个定时器的内容是,输出i。但是所有定时器创建号时并没有立刻执行,而是会在3秒后执行。
- 现在3秒过后,再输出i,此时i的值已经变成10了,所以是10个10
解决方案: 上面例子的主要原因不是因为访问的都是同一个i吗,那我们让它访问的不是同一个i就可以了。那这个怎么办呢。就要用到我们的立即执行函数。代码如下
for(var i = 0; i < 10; i ++) {
(function (i) {
setTimeout(function () {
console.log(i);
}, 3000)
}(i))
}
这个时候,i 作为函数的变量传了进去,现在定时器要输出的 i 就是自己函数里面的这个 i,不是全局中的那个 i。
作用域
在js中作用域主要有两种,一种是全局作用域,一种是函数作用域。当然还有一个es6的块级作用,这里不作介绍。 全局作用域中有一个全局对象window。这个window会记录所有在全局中定义的变量还有函数。比如现在定义了一个变量a,这个a就会被保存到window之上
var a = 10;
console.log(window.a); // 10
window.a = 20; // 修改了window上的a,声明的变量a也会受影响,说明这是同一个东西
console.log(a); // 20
这是一个不好的现象,很多时候我们定义变量并不想他保存到window上面,因为在实际的开发中,肯定会有很多的js文件,而且肯定是不同的人写的。如果第一个文件定义了一个变量a,第二个文件又定义了一个变量a,这个时候就冲突了。
解决方案: 使用立即执行函数改变作用,这就是IIFE的作用。因为函数中会产生一个新的作用域,不会把里面的东西保存到window之上。
(function () {
var a = 10;
}())
console.log(window.a) // undefined
此时window上,就不会保存函数内的变量和函数