什么是链式调用
概念
连续不断调用一个对象中的任一方法
原理
调用完一个方法后,返回调用当前方法的对象(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函数重新封装实现链式调用,这只是其中一个方法,也不是最优版,欢迎大家提出意见和建议