什么是立即执行函数及与闭包的关系如何

610 阅读3分钟

立即执行函数的三种写法:

  • 第一种
(function(){
    
})();
  • 第二种
function(){
    
}())
  • 第三种
!function(){
    
}()

立即执行函数的作用

立即执行函数只有一个作用:创建一个独立的作用域。这个作用域里面的变量,外面访问不到(即避免了「变量污染」)。

关于立即执行函数经典面试题:

var liList = ul.getElementsByTagName('li')
for(var i=0; i<6; i++){  
    liList[i].onclick = function(){
            alert(i)   // 为什么 alert 出来的总是 6,而不是 012345 
    }
}

因为输出的 i 是全局作用域的,当循环结束后 i 的值是 6,所以输出的 i 就是6。

用立即执行函数可以解决这个问题。

var liList = ul.getElementsByTagName('li')
for(var i=0; i<6; i++){
  (function(j){
      liList[j].onclick = function(){
            alert(j) // 0、1、2、3、4、5
      }
   })(i);
}
​

因为 JS 中调用函数传递参数都是值传递 ,所以当立即执行函数执行时,首先会把参数 i 的值复制一份,然后再创建函数作用域来执行函数,循环5次就会创建5个作用域,所以每个 li 元素访问的都是不同作用域的 i 的值 。

立即执行函数和闭包的区别

for (var i = 0; i < 5; i++) {
    (function (i) {
            setTimeout(function () {
                        console.log(i);
            }, 1000);
     })(i);
 }
 console.log(i);
//setTimeout 依次输出 0 1 2 3 4 5

第一个 5 很好输出,因为for循环以后i就会变成5,剩下的我们可以使用立即执行函数来做。首先 JS中调用函数传递参数都是值传递 ,所以当立即执行函数执行时,首先会把参数 i 的值复制一份,然后再创建函数作用域来执行函数,循环5次就会创建5个作用域,所以1秒后几乎会同时输出 0 1 2 3 4 。

上面的现象也可以说是闭包,因为在外层的 function 里面还包含着 setTimeout 里面的 function 函数,而里面的 function 函数就访问了外层 function 的 i 的值,由此就形成了一个闭包。每次循环时,将 i 的值保存在一个闭包中,当 setTimeout 中定义的操作执行时,就会访问对应闭包保存的 i 值,所以输出 0 1 2 3 4。

立即执行函数和闭包没有什么关系,只是两者会经常结合在一起使用而已,但两者有本质的不同。

立即执行函数和闭包只是有一个共同优点就是能减少全局变量的使用。

立即执行函数只是函数的一种调用方式,只是声明完之后立即执行,这类函数一般都只是调用一次,调用完之后会立即销毁,不会占用内存。

闭包则主要是让外部函数可以访问内部函数的作用域,也减少了全局变量的使用,保证了内部变量的安全,但因被引用的内部变量不能被销毁,增大了内存消耗,使用不当易造成内存泄露。

\