一个可以在Javascript中同时进行组合和链式调用(点符号)的函数

5

我正在尝试转换一个旧的API,它使用了很多点符号链式调用,需要保留,例如:

[1,2,3,4].newSlice(1,2).add(1) // [3]

我希望在这个例子中加入组合的函数式风格,使用Ramda,但lodash或其他库也可以:
const sliceAddOne = R.compose(add(1), newSlice(1,2)) 
sliceAddOne([1,2,3,4])// [3]

我的问题是如何在我的函数newSlice中实现链式和组合,这个函数应该长什么样?
我有一个小的jsBin示例。
1个回答

3

编辑

我觉得我最初误解了您的意思。您需要一个函数f,可以通过调用以下方式来使用:

f(...args)(someObj) ===  someObj.f(...args)

我会这样做
// infix
Array.prototype.newSlice = function(x,y) { return this.slice(x,y) }

// prefix 
const newSlice = (x,y) => F => F.newSlice(x,y)

该设计非常好,因为您可以在任何希望具有“newSlice”功能的对象上实现“newSlice”,并且前缀函数将正常工作。这也允许您在每种对象类型(数组,字符串,其他...)上拥有独特的“newSlice”实现,因为我们切片的底层数据可能不同 - 您可以获得所有这些,而无需在函数体内进行愚蠢的条件“this”检查。

// newSlice :: [a] -> (Integer,Integer) -> [a]
Array.prototype.newSlice = function(x,y) {
  return this.slice(x,y)
}

// newSlice :: String -> (Integer,Integer) -> String
String.prototype.newSlice = function(x,y) {
  return this.substring(x,y)
}

// even on a custom object
class LottoTicket {
  constructor(...nums) { this.nums = nums }
  newSlice(x,y) { return this.nums.slice(x,y) }
}

// newSlice :: (Array, String) a => (Integer,Integer) -> a -> a
const newSlice = (x,y) => F => F.newSlice(x,y)

// use it in prefix position
console.log(newSlice(1,2)([1,2,3,4]))              // [2]
console.log(newSlice(1,2)("abcd"))                 // 'b'
console.log(newSlice(1,2)(new LottoTicket(9,8,7))) // [8]

// use it infix position
console.log([1,2,3,4].newSlice(1,2))                // [2]
console.log("abcd".newSlice(1,2))                   // 'b'
console.log((new LottoTicket(9,8,7)).newSlice(1,2)) // [8]


谢谢指点,这就是为什么我倾向于使用Ramda,因为所有函数都是柯里化的 :) - cmdv
@cmdv,看来我误解了你最初的意图。我重新理解后修改了我的回答。 - Mulan
谢谢,非常详尽,对我来说有很多可以带走的东西。 - cmdv
如果我要为Array + String添加新的原型,有什么方法可以在函数本身中保持这个内联?我有100多个需要像这样转换的函数,并担心名称冲突。 - cmdv
它们都在全局 Global.prototype.slice 上,但是想要 ES6 导出和隔离函数,而不是依赖于父子关系。我将采用您的解决方案 http://jsbin.com/gihepevaxe/1/edit?js,console - cmdv
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接