使用字符串数组创建嵌套函数的对象以形成对象键

时间:2014-10-04 13:30:37

标签: javascript coffeescript method-chaining

我使用以下构造作为Mock对象,该对象充当具有可链接方法的对象:

PlayerNull =
  find : ->
    populate : ->
      exec : (callback) ->
        callback false, false

在我的测试中,我将真实模型替换为此Mock对象,我的控制器依次调用每个函数,如:

Model.find().populate().exec(callback)

当我发现自己多次使用时,我很好奇是否可以使用以下形式的辅助函数创建辅助函数来简化(略微):

PlayerNull = helper.mockNest ['find', 'populate', 'exec'], (callback) ->
  callback false, false

我来了以下功能代码,但这不起作用:

exports.mockNest = (func_names, func_final) ->
  func_names.reverse()
  func_next = func_final
  for func_name in func_names
    _func_next = func_next.bind({})
    _next = {}
    _next[func_name] = ->
      _func_next
    func_next = _func_next
  func_next

我已经意识到我需要克隆func_next每个循环,否则引用似乎得到维护,并且分配给func_next似乎只是改变了以前的所有赋值。

2 个答案:

答案 0 :(得分:2)

是的,您已正确识别问题,未能保留引用,这是典型的closure in a loop问题。

但是,克隆这个功能在这里确实没有帮助,你的实际问题是

_next[func_name] = ->
  _func_next

_func_next变量上创建一个闭包,在每次循环迭代中都会对其进行修改。

应该是

exports.mockNest = (func_names, func_final) ->
  func_names.reverse()
  func_next = func_final
  for func_name in func_names
    next = {}
    next[func_name] = func_next
    func_next = do (_next = next) ->
      () ->
        _next
  func_next

答案 1 :(得分:0)

感谢Bergi的解释,我找到了以下解决方案:

exports.mockNest = (func_names, func_final) ->

  # Assign the last function to the provided func_final
  func_name_final = func_names.pop()
  func_next = {}
  func_next[func_name_final] = func_final

  # Reverse the array so we build the object from last to first.
  func_names.reverse()
  for func_name in func_names
    ignore = do (func_name, _func_next = func_next) ->
      func_next = {}
      func_next[func_name] = ->
        _func_next
      return
  func_next

为了解释这些变化,我需要保留提供的func_final,所以我必须在循环之前分配。

此外,我需要将do块分配给变量ignore,否则Coffeescript会将该函数编译到不同位置,其中对func_next所做的更改是无序的。分配可确保放置do块。