[路飞]每日一答:谈谈闭包的应用场景

733 阅读2分钟

谈谈闭包的应用场景

导语:在之前简单介绍了一下闭包以及闭包的作用。这一期聊一聊闭包的应用场景。

一.单例的实现

所谓单例就是在全局中,这个类提供了一种访问其唯一的对象的方式。注意关键词就是这个对象是唯一的,也就是说调用该单例创建方法都会返回同一个对象。

function Person() {
  this.name = 'ouda'
}

Person.sharedInstance = (function () {
  var instance;
  return function () {
    if (!instance) {
      instance = new Person()
    }
    return instance;
  }
})()

const p1 = Person.sharedInstance()
const p2 = Person.sharedInstance()
console.log(p1 === p2)

p1p2 都是通过 sharedInstance() 进行创建的,他们访问到的都是同一个内部变量 instance,形成了一个闭包,所以 p1p2指向的都是同一个对象。那么只要通过这个方法创建出来的对象就是同一个,且唯一,这就是闭包在创建单例的应用场景。

二.属性的私有化

当我们对一个变量想要进行保护,不想给外部直接访问时,我们可以利用闭包将变量私有化。

假设这样一个应用场景,在一个游戏中,你有3条命,当你达到条件时,生命+1,触发另一种场景时生命 -1,为了保护生命值这个变量只能够按照规则 +1 或者 -1,不允许被别的函数修改或者在其他作用域访问,我们可以这样做:

function Role() {
  var life = 3

  this.addLife = function () {
    life++
    return life
  }

  this.minLife = function () {
    life--
    return life
  }

  this.getLife = function () {
    return life
  }
}

const role = new Role()
console.log(role.addLife()) // 4
console.log(role.addLife()) // 5
console.log(role.minLife()) // 4
role.life = role.life + 100
console.log(role.getLife()) // 4

可以发现 Role 下的 life变量我们只能通过 addLifeminLife 这两个方法进行改变,并且改变的规则在函数内部自己规定。直接通过 role.life是访问不到该变量的,更不用说试图去更改他的值了。

三.函数的科里化

什么是科里化?

柯里化(currying),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

如果要实现一个数字的累加器(1+2+3+4....)

初级写法:

function sum(a, b) {
  return a + b
}

let res = sum(1, 2)
res = sum(res, 3)
res = sum(res, 4)
console.log(res) // 10

需要加多少次就写多少个sum函数。

中级写法:

function sum() {
  const numbers = Array.from(arguments)
  return numbers.reduce((a, b) => { return a + b })
}
console.log(sum(1, 2, 3, 4, 5, 6)) //21

通过函数 arguments 巧妙地将参数个数不作限制。

科里化高级写法:

function sum() {
  var numberList = Array.from(arguments)
  var _sum = function () {
    numberList = numberList.concat(Array.from(arguments))
    return _sum
  }
  _sum.valueOf = function () {
    return numberList.reduce((a, b) => { return a + b })
  }
  _sum.toString = function () {
    return numberList.reduce((a, b) => { return a + b })
  }
  return _sum
}

const res = +sum(1, 2, 3)(4)(5, 6)
console.log(res)

调用更加随心所欲,可以不限制参数,并且可以链式调用,函数的科里化,就是用到了闭包实现的。 numberList就是闭包中的私有变量。