立即执行函数

250 阅读2分钟

1 概念

  • 声明一个匿名函数
  • 用()把这个函数包起来(为了兼容JS语法),当然你也可以这样做
(function(){alert('我是匿名函数')} ()) // 用括号把整个表达式包起来
(function(){alert('我是匿名函数')}) () //用括号把函数包起来
!function(){alert('我是匿名函数')}() // 求反,我们不在意值是多少,只想通过语法检查
+function(){alert('我是匿名函数')}()
-function(){alert('我是匿名函数')}()
~function(){alert('我是匿名函数')}()
void function(){alert('我是匿名函数')}()
new function(){alert('我是匿名函数')}()
  • 然后在匿名函数后面接一对括号 (),调用这个匿名函数。

2 作用

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

3 实战

以一个著名的面试题为例:

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

why总是6?因为 i 是贯穿整个作用域的,而不是给每个 li 分配了一个 i

怎么解决这个问题呢?用立即执行函数给每个 li 创造一个独立作用域即可(当然还有其他办法):

var liList = ul.getElementsByTagName('li')
for(var i=0; i<6; i++){
  !function(i){
    liList[i].onclick = function(){
      alert(i) // 0、1、2、3、4、5 ,里面的i
    }
  }(i) //外面的i
}

需要注意的是,外面的 i 和里面的 i 是不一样的(里面的 i 换成 j 就好理解了)

4 拓展

  • 使用let 语法糖,也可以输出 0、1、2、3、4、5
var liList = ul.getElementsByTagName('li')
for(let i=0; i<6; i++){ //对,就是这里换成let
  liList[i].onclick = function(){
    alert(i) //0、1、2、3、4、5
  }
}
  • let,就是自动帮你完成了上面立即执行函数的功能而已
for(let i=0; i<6; i++){
 //下面这一行你是看不到的,JS自动帮你做了
 //不要使用var这个sb语法,因为var语法只有在函数里才是局部的,否则他会自动变成全局的
  ..........
  let j=i
  ..........
  liList[j].onclick = function(){
    alert(j) //0、1、2、3、4、5
  }
}
  • 如果你把let放在了外面,输出的依然是6个6
let i //let放在for循环外面
for(i=0; i<6; i++){
    .......
}