在CoffeeScript中重新实现UnderscoreJS链接

时间:2015-04-18 21:47:58

标签: javascript coffeescript underscore.js

首先, 我阅读了related articles,感觉它们不适合我,因为我使用的是一系列继承的方法,而不是一些我可以轻易改变的算术函数。其次,谷歌搜索'javascript chaining method'的结果主要与jQuery和D3有关。看起来,JavaScript chain方法令人惊讶地记录不足。

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

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

_。链

_.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]

1 个答案:

答案 0 :(得分:1)

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

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

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

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

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

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

现在,我们关闭fn,而不是关闭fn以便稍后使用(之后,它不会是我们想要的f),我们立即绑定fn成为_.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 当前值。

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

{{1}}

您可以使用您的示例进行检查,看看它现在给出了正确答案。