在 CoffeeScript 中重新实现 UnderscoreJS 链接

Reimplementing UnderscoreJS chaining in CoffeeScript

首先, 我阅读了关于此的 并觉得它们不适合我,因为我使用的是我继承的一系列方法,而不是一些我可以轻松更改的算术函数。其次,谷歌搜索 'javascript chaining method' 的结果主要与 jQuery 和 D3 有关。 JavaScript chain 方法的文档似乎少得令人惊讶。

我正在尝试 implement underscore 在 CoffeeScript 中。我正在研究 _.chain 方法。我正在将下划线方法装饰为 newObject 然后 returning 它。我有一个名为 value 的私有变量,它应该是被链式方法调用修改的值。在 returned newObject 上调用 getValue() 应该 return 私有 value 变量。

由于某些原因,当我在 newObject 上调用方法时,私有 value 变量没有改变。下划线方法被正确柯里化,但在调用函数时它们不会改变。我尝试阅读 underscore source code,但他们似乎以完全不同的方式构建了链式方法,如果不重构我的下划线对象的构造方式,我无法复制。

_.chain

_.chain = (v) ->
  newObj = {}
  value = v
  newObj.getValue = -> value
  for name, fn of _
    if typeof fn is 'function'
      newObj[name] = (callback, otherVal) ->
        value = fn(value, callback, otherVal)
        newObj
  newObj

示例:

var a = _.chain([1,2,3,4]);
a.map(function(value) {
  return value + 5;
})
a.getValue().getValue()
>>>[1, 2, 3, 4]

问题与闭包行为有关(毕竟这是 javascript)。问题出现在这里:

newObj[name] = (callback, otherVal) ->
  value = fn(value, callback, otherVal)
  newObj

fn 的值已关闭,只要在 newObj 上调用与 name 关联的函数时就会使用该值。问题在于 fn 的值在 chain 函数的整个生命周期中都会发生变化,因此关闭值也会发生变化。特别是,在 chain 退出后,您附加到 newObj 的每个下划线函数的闭包中 fn 的值将是 for name, fn of _ 中最后迭代的任何函数环形。在这种情况下,该函数是 chain,因此当您在示例中调用 map 时,当解释器命中行 value = fn(value, callback, otherVal) 时,fnchain 函数。

这就是为什么您需要在您的示例中调用 getValue 两次:a.map(...) 在内部调用 chain,因此它 returns 是一个链式对象。

为了解决这个问题,我们可以使用 IIFE,这样您附加到 newObj 的函数就不会关闭 fn,而是关闭您想要的实际函数:

newObj[name] = ((f) ->
  (callback, otherVal) ->
    value = f(value, callback, otherVal)
    newObj
  )(fn)

现在,我们关闭 f,而不是关闭 fn 供以后使用(以后,它不会是我们想要的 fn)立即绑定为 fn.

current

这是完整的固定版本,在 Coffeescript 中:

_.chain = (v) ->
  newObj = {}
  value = v
  newObj.getValue = -> value
  for name, fn of _
    if typeof fn is 'function'
      newObj[name] = ((f) ->
        (callback, otherVal) ->
          value = f(value, callback, otherVal)
          newObj
      )(fn)
  newObj

你可以用你的例子检查它,看看它现在给出了正确的答案。