立即执行函数与作用域

621 阅读3分钟

立即执行函数(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。那为什么会这样呢。 原因是这样的

  1. 循环里面定义了一个定时器,在3秒钟之后执行。
  2. 声明了一个变量i,这个i是在全局上定义的。
  3. 每一次循环的时候,都会创建一个定时器,然后 i ++。这个时候定时器。
  4. 当i加到10的时候,i < 10为false,不会进入循环,这个时候已经创建了10个定数器了,这个定时器的内容是,输出i。但是所有定时器创建号时并没有立刻执行,而是会在3秒后执行。
  5. 现在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上,就不会保存函数内的变量和函数