链式调用

309 阅读2分钟

什么是链式调用

概念

连续不断调用一个对象中的任一方法

原理

调用完一个方法后,返回调用当前方法的对象(return this

优点

在获得与普通函数调用结果相同情况下,代码量大幅减少,逻辑集中清晰且易与查看和修改

常见例子

  • Promise.then.then.catch.finally .....
  • vue createApp().use().use().mount()

简单实现

/**
 * 最重要的部分为方法run和sing的返回值为this;
 */
 function Person (name) {
  this.name = name;
  
  this.run = () => {
    console.log(name + 'run');
    return this;
  }
  
  this.sing = () => {
    console.log(name + 'sing');
    return this;
  }
}

var person = new Person('小红');

// 方式1
person.run();		// 小红run
person.sing();          // 小红sing

// 方式2
person.run().sing();	// 小红run
                        // 小红sing

// 结论:方式1和方式2结果完全相同,但方式2代码更优,代码量少,可读性强

手写Math对象的链式调用

基础版

/**
 * Math的链式调用
 * 封装Math工具函数
 * 问题:多次调用时会延续前一个数据的结果
 */
function ChainMath (val) {
  this.value = val
  // 开根号
  this.sqrt = (a) => {
    this.value = Math.sqrt(this.value, a);
    return this;
  }
  // 求方
  this.pow = (a) => {
    this.value = Math.pow(this.value, a);
    return this;
  }
}

const myMath = new ChainMath(16);

const result = myMath.sqrt(2).sqrt(2).pow(2);

console.log(myMath.value);      // 4 ? myMath实例中的value不应更具中间计算值改变
console.log(result.value);	// 4

// 存在的问题:myMath中的value值会根据当前计算过程改变,只能重新实例化myMath才能重置数据

优化版

/**
 * Math的链式调用
 * 封装Math工具函数
 * 问题:多次调用时会延续前一个数据的结果
 * 解决方案:每次链式调用时新生成一个实例,确保数据相互独立
 */

function ChainMath (val = ChainMath.prototype.value) {
  // 每一次链式调用都会重置value值,作为初始值
  ChainMath.prototype.value = val;
  // 非ChainMath实例时创建实例,隔离变量
  if (!(this instanceof ChainMath)) {
    return new ChainMath(val);
  }
  this.toString = function () {
    console.log('toString')
  }
}

ChainMath.prototype.sqrt = function (a) {
  // 新实例隔离变量
  const instance = ChainMath();
  instance.value = Math.sqrt(this.value, a);
  return instance;
}

ChainMath.prototype.pow = function (a) {
  // 新实例隔离变量
  const instance = ChainMath();
  instance.value = Math.pow(this.value, a);
  return instance;
}

const myMath = new ChainMath(16);

const result1 = myMath.sqrt(2).pow(3);          // (16 ^ 0.5) ^ 3 = 64
const result2 = myMath.sqrt(2).pow(2);          // (16 ^ 0.5) ^ 2 = 16
const result3 = myMath.sqrt(2).sqrt(2).pow(2);  // ((16 ^ 0.5) ^ 0.5 ) ^ 2 = 4

console.log('(16 ^ 0.5) ^ 3 = ', result1.value)			// 64
console.log('(16 ^ 0.5) ^ 2 = ', result2.value)			// 16
console.log('((16 ^ 0.5) ^ 0.5 ) ^ 2 = ', result3.value)	// 6

// 结论:每次使用myMath实例时,其中的value值都为初始值

本文通过对Math函数重新封装实现链式调用,这只是其中一个方法,也不是最优版,欢迎大家提出意见和建议