如何在不使用原型的情况下链接函数

How to chain functions without using prototype?

本文关键字:情况下 链接 函数 原型      更新时间:2023-09-26

我一生中收集了一堆有用的函数。

function one(num){
    return num+1;
}
function two(num){
    return num+2;
}

我可以用two(two(one(5)))打电话给他们

但我更愿意使用(5).one().two().two()

如何在不使用原型的情况下实现这一点?

我试图看看下划线链是如何工作的,但他们的代码太密集了,无法理解它

点语法是为对象保留的。所以你可以做一些类似的事情

function MyNumber(n) {
    var internal = Number(n);
    this.one = function() {
        internal += 1;
        // here comes the magic that allows chaining:
        return this;
    }
    // this.two analogous
    this.valueOf = function() {
        return internal;
    }
}
new MyNumber(5).one().two().two().valueOf(); // 10

或者,您将在本机 Number 对象/函数的原型上实现这些方法。这将允许(5).one()...

为了避免

像@Bergi的解决方案那样在链的末端调用toValue,您可以使用带有附加方法的函数。当尝试将其转换为基元类型时,JS将自动调用toValue

function MyNumber(n) {
    function x () { }
    x.one = function() { n++; return this; };
    x.valueOf = function() { return n; };
    return x;
}

然后

MyNumber(5).one().one()
> 7

一个不错的通用替代方案是创建自定义函数组合函数

var go = function(x, fs){
   for(var i=0; i < fs.length; i++){
       x = fs[i](x);
   }
   return x;
}

你可以这样称呼它:

go(5, [one, two, two])

我个人不太喜欢方法链接,因为它将您限制为一组预定义的函数,并且"链接对象"内部的值与外部的自由值之间存在阻抗不匹配。

另一种选择是使用 lodash 流函数。例如:

var five = _.flow(one, two, two)
five(5)

我更喜欢为变量分配一个新链。它给它一个明确的名字,并鼓励重复使用。

顺便说一句,lodash 还有助于将额外的参数传递给链的函数。例如:

var addFive = _.flow(
   _.partialRight(_.add, 1),
   _.partialRight(_.add, 2),
   _.partialRight(_.add, 2)
)

还有许多其他有用的函数可以帮助功能链,例如,部分扩散翻转否定等。

基本上JS中没有函数组合。即使有,也会与你在问题中提到的顺序相反。即two . two . one因为数学声明了这样的组合运算符。所需的顺序称为管道。

话虽如此,如果你真的想要用点运算符进行组合,你仍然可以通过Proxy对象重载.运算符来实现。这是一个有点复杂的话题,您可以查看这篇不错的博客文章以获取一些想法。

但是,满足您需求的最简单方法是将函数数组减少为;

var pipe = (fs,x,y) => fs.reduce((r,f) => f(r),{x,y}),
    fs   = [ ({x,y}) => ( x++
                        , y++
                        , {x,y}
                        )
           , ({x,y}) => ( x*=3
                        , y*=3
                        ,{x,y}
                        )
           , ({x,y}) => ( x--
                        , y--
                        , {x,y}
                        )
           ];
var {x,y} = pipe(fs,1,2);
console.log(x,y);