美文网首页饥人谷技术博客
理解闭包、立即执行函数、异步和回调

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

作者: 马建阳 | 来源:发表于2017-08-17 14:19 被阅读477次

闭包

什么是闭包

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

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('异步任务的结果')都是回调,一个是名词,一个是动词。

相关文章

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

    闭包 什么是闭包 一个函数使用了它外面的变量,这种用法就是闭包。闭包是一个马后炮的总结。 那为何要这样做呢(搞得这...

  • 前端入门11 -- JavaScript之Promise

    回调函数 回调函数分为两种类型,分别为同步回调与异步回调; 同步回调:会立即执行,完全执行完了才结束,不会放入回调...

  • 理解立即执行函数和闭包

    立即执行函数 写代码时尽量不要使用全局变量,因为很可能会相互覆盖 在 java 语言中我们可以用 { } 将代码包...

  • Day4 闭包

    闭包允许函数访问定义时的词法作用域回调函数基本上都是闭包模块利用闭包隔离变量,暴露公共API(也会伴随IIFE立即...

  • es5核心技术

    立即执行函数 函数提升和变量提升 闭包 this 原型链实现继承

  • 从回调函数到 async await,理清异步编程解决方案

    异步解决方案历程 1. 回调函数 回调函数是最开始的异步解决方案,在异步代码执行完后去执行回调函数 这样做有几个缺...

  • 立即执行函数和闭包

    立即执行函数: 一、计时器 一次性定时器 setTimeOut(function(){ //1秒后执行 },100...

  • 闭包和立即执行函数

    闭包:先来看一个题目:实现一个函数,每次调用自增1 你有可能会想用全局变量,计数的时候将它加一,但是全局变量有风险...

  • 闭包和立即执行函数

    闭包闭包:内部的函数引用了外部的函数的变量,则产生闭包。闭包的作用:把变量封装在函数中,只有内部函数可以用,让函数...

  • 关于立即执行函数IIFE

    [译] JavaScript:立即执行函数表达式(IIFE) IIFE保存闭包的状态 就像当函数通过他们的名字被调...

网友评论

    本文标题:理解闭包、立即执行函数、异步和回调

    本文链接:https://www.haomeiwen.com/subject/tlagrxtx.html