理解闭包、立即执行函数、异步和回调

闭包

什么是闭包

一个函数使用了它外面的变量,这种用法就是闭包。闭包是一个马后炮的总结。

function xxx(){
    var lives = 30
    var bug = 'salkdjaslkdjaslkjd...100MB'   // IE bug
    function die(){
      lives -= 1
      return lives
    }
    return die
}

var dieFn = xxx()
// here
var currentLives = dieFn()

那为何要这样做呢(搞得这么麻烦):

闭包的作用

闭包常常用来「间接访问一个变量」。换句话说,「隐藏一个变量」。
因为如果是全局变量,容易被改,如果是局部变量,别人又访问不到。

上面这样用闭包,就可以用dieFn()来修改lives。

闭包造成内存泄露?

内存泄露是指你用不到(访问不到)的变量,依然占居着内存空间,不能被再次利用起来。

闭包里面的变量明明就是我们需要的变量(lives),所以不是内存泄露

为何有人说是?
因为 IE。IE 有 bug,IE 在我们使用完闭包之后,依然回收不了闭包里面引用的变量。

立即执行函数

什么是立即执行函数

声明一个匿名函数,立即执行它,就是立即执行函数

!function (){
    var lives = 30
    console.log(lives)
}.call()

感叹号可以换成 + - ~ 等符号,也可以换成括号。

那为什么要有这么个东西(好麻烦)

立即执行函数的作用

只有一个作用:创建一个独立的作用域。
这个作用域里面的变量,外面访问不到(即避免「变量污染」)。
这个作用不就恰恰是闭包所需要的吗!!!
所以之前的函数可以写成

!function xxx(){
    var lives = 30
    var bug = 'salkdjaslkdjaslkjd...100MB'   // IE bug
    function die(){
      lives -= 1
      return lives
    }
    return die
}.call()

举例:

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
  }
}

因为在点击之前i早变成了6,每个监听的元素都为6。
那么怎么解决这个问题呢?用立即执行函数给每个 li 创造一个独立作用域即可

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

在立即执行函数执行的时候,i 的值被赋值给 ii,此后 ii 的值一直不变。

i 的值从 0 变化到 5,对应 6 个立即执行函数,这 6 个立即执行函数里面的 ii 「分别」是 0、1、2、3、4、5。

异步+回调

什么是异步

同步:一定要等任务执行完了,得到结果,才执行下一个任务。

function taskSync = function(){
  return '同步任务的返回值'
}

var result = taskSync() // 那么 result 就是同步任务的结果
otherTask()             // 然后执行下一个任务

异步:不等任务执行完,直接执行下一个任务。相当于给前一个任务加个警报器,任务好了再告诉你去执行。

function taskAsync = function(){
  var result = setTimeout(function(){
    console.log('异步任务的结果')
  }, 3000)
  return result
}

var result = taskAsync() // result 不是异步任务的结果,而是一个 timer id。不懂?因为现在我是无法得到3秒后的result,只会得到他的定时器。
otherTask()              // 立即执行其他任务,不等异步任务结束

什么情况下需要用到异步?

如果几个任务互相独立,其中一个执行时间较长,那么一般就用异步地方式做这件事。

什么是回调

callback 就是(传给另一个函数调用的)函数。把括号里面的内容去掉,简化成:callback 就是一种函数。
具体来讲:
当一个函数 A 被作为参数传给另一个函数时 B,那么这个函数 A 就叫做回调(名词)。B 中调用 A 函数的过程,也叫做回调(动词)。
那回调有什么用呢?

回调的作用

回调通常用在获取「异步任务」的结果
之前异步的代码也可写成如下(为理解起见我简化了)

function async(fn){
   setTimeout(function(){
    fn('异步任务的结果')
  }, 3000)
  return 
}//函数声明

async(function  (xxx){
    console.log(xxx)
}) // 函数调用。3秒后执行fn,xxx 是异步任务的结果
otherTask()             

过程简单来说就是我调了async函数,然后在async函数里它调了fn函数(此时fn相当于是我传的参数function),调用的时候把'异步任务的结果'(此时'异步任务的结果'相当于xxx)传了出来。
其中function (xxx){ console.log(xxx)}和fn('异步任务的结果')都是回调,一个是名词,一个是动词。

你可能感兴趣的:(理解闭包、立即执行函数、异步和回调)