ES 编码实践 —— 链式调用

published

链式调用的形式

obj.m1().m2().m3()....mN()

链式调用的优缺点

  • 优点
    • 减少了代码量,降低了冗余度
  • 缺点
    • 占用了函数的返回值

实现方法

方法 1:实例方法返回对象自身 —— 返回 this

class Counter {
  constructor (num) {
    this.number = num
  }

  add (num) {
    this.number += num
    return this
  }

  minus (num) {
    this.number -= num
    return this
  }

  show () {
    console.log(this.number)
    return this
  }
}

const i = new Counter(10)
i.add(5).add(5).minus(2).show().minus(2).show()

这种方法的缺点:每定义一个类,其方法体中都要返回 this。 如果是已经写好的类,打算要让它支持链式调用,怎么办?批量修改原型方法。但是,手动来做很繁琐。写些辅助函数来自动完成这个事儿吧:

class Counter {
  constructor (num) {
    this.number = num
  }

  add (num) {
    this.number += num
  }

  minus (num) {
    this.number -= num
  }

  show () {
    console.log(this.number)
  }
}

// add `return this` for method
function addThis (class_, method, fn) {
  class_.prototype[method] = function (...args) {
    fn.apply(this, [...args])
    return this
  }
}

// add `return this` for multiple methods
for (let m of ['add', 'minus', 'show']) {
  addThis(Counter, m, Counter.prototype[m])
}

const i = new Counter(10)
i.add(5).add(5).minus(2).show().minus(2).show()

方法 2:利用函数代理对象

class Counter {
  constructor (num) {
    this.number = num
  }

  add (num) {
    this.number += num
  }

  minus (num) {
    this.number -= num
  }

  show () {
    console.log(this.number)
  }
}

function chain (obj) {
  function f (method, ...args) {
    if (arguments.length === 0) {
      return obj
    }

    obj[method](...args)

    return f
  }

  return f
}

const i = new Counter(10)
chain(i)('add', 5)('add', 5)('minus', 2)('show')('minus', 2)('show')

这种方式用了闭包,比较费内存,如果没什么必要,还是用别的方法。