闭包

2018-06-04  本文已影响0人  ZombieBrandg

闭包

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

魂斗罗例子

现在假设我们在玩魂斗罗。通过秘籍调出了 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

更为详细的博客地址

彭玉芳闭包博客地址

上一篇下一篇

猜你喜欢

热点阅读