闭包

作者: ZombieBrandg | 来源:发表于2018-06-04 23:04 被阅读0次

    闭包

    闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常用方式,就是在一个函数内部创建另一个函数。

    魂斗罗例子

    现在假设我们在玩魂斗罗。通过秘籍调出了 30 条命,每当我们死亡一次就会减一条命。

    有个原则就是尽量不要创建全局变量,并且我们的 lives 变量不能暴露出来防止被别人改动,所以我们用函数封装起来。

    function person() {
      let lives = 30
    }
    

    然后再给它添加一个 die 函数,触发后生命减 1。由于不能写在全局作用域里,所以我们把它写到 person 里面。

    function person() {
      let lives = 30
      function die() {
        lives -= 1
        return lives
      }
    }
    

    但是问题来了,根据 js 的作用域原理,我们在函数外面是没办法调用函数里面的变量的。这时候就要用到闭包了。

    函数特性

    在讲闭包之前我们先仔细探究一下函数的运行机制。

    我们都知道函数接受两个参数对象,一个是隐藏的 this 对象(只有在 call 和 apply 方法里可以当做第一个参数传入),另一个是 arguments 类数组对象(里面保存着除 this 之外的所有参数)。

    可以把函数具象成一个房间。这个房间有一扇前门,一扇后门。前门就是 arguments 对象,所有的实参值都在这里赋给形参,然后进入函数。后门就是 return,所有返回值都从这里出去。

    现在再看上面的例子,我们要从 person 函数外调用里面的 die 函数,理所当然的应该把 die 函数当做返回值送出 person 这个房间。

    魂斗罗例子续

    在经过一些判断(被子弹打到、碰到敌人、掉到沟里)后,我们的生命减 1 了。

    function person() {
      let lives = 30
      return die = function () {
        lives -= 1
        return lives
      }
    }
    ...
    if ( ... ) {
      person()() // 29
      person()() // 29
    }
    ...
    

    但是这样又有个问题,每次调用都会重置 lives 为 30,导致 die 触发后 lives 一直是 29。

    可以添加一个中间变量 die,跟 die 函数同名是为了增加可读性。

    let die = person()
    die() // 29
    die() // 28
    

    这样每次死亡只要调用一下 die() 就可以了。

    面向对象写法

    上面的功能也可以用面向对象来写

    let person = {
      lives: 30,
      die: function () {
        this.lives -= 1
        return this.lives
      }
    }
    person.die() // 29
    person.die() // 28
    

    用这种方法写例子可以。但是我们每次进游戏,都会创建一个新的人物,这就要用到构造函数来创建对象,涉及到了构造函数的私有变量和特权方法。另一篇博客会详细介绍函数的私有变量和特权方法。

    本篇博客转载自http://www.lclscofield.com

    更为详细的博客地址

    彭玉芳闭包博客地址

    相关文章

      网友评论

          本文标题:闭包

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