【问题标题】:Backbone and bindAll: "func is undefined"Backbone 和 bindAll:“func 未定义”
【发布时间】:2011-09-30 13:59:06
【问题描述】:

我在使用 bindAll 时遇到了问题。我得到的错误是func is undefined。对我做错了什么有什么想法吗?

我都试过了

  • bindAll(因上述错误而失败)和
  • 个人binds(不工作)
window.test = Backbone.View.extend({

  collection: null

  initialize: ->
    console.log('initialize()')
    console.log(this)
    # _.bindAll(this, ["render", "foo"])
    _.bind(this.render, this) # these don't throw errors, but binding won't work
    _.bind(this.foo, this) 
    @collection = new Backbone.Collection()
    @collection.bind "add",     @render
    @collection.bind "add",     @foo
    @render()

  foo: ->
    # won't be bound to the view when called from the collection
    console.log("foo()")
    console.log(this)
    console.log(this.collection) # undefined (since this is the collection, not the view)

  render: ->
    console.log("render()")
    console.log(this)
    return this

})
testInstance = new window.test();
# using _.bind instead of bindAll we get past this point, however this won't be the view
testInstance.collection.add({})

【问题讨论】:

    标签: javascript binding backbone.js coffeescript underscore.js


    【解决方案1】:

    你使用的是 CoffeeScript,你不需要下划线的绑定。 CoffeeScript 内置了它。只需使用“胖箭头”

    foo: =>
        #Your foo implementation goes here
    render: =>
        # your render implementation goes here
    

    在此处搜索“胖箭头”:http://jashkenas.github.com/coffee-script/

    但是,对于_.bindAll,您不需要将方法名称作为数组提供。您可以使用 _.bindAll(this)_.bindAll(this, 'render', 'foo') (方法名称是 var args,而不是显式列表)。看看有没有帮助。

    【讨论】:

    • 没有设法让粗箭头在 Backbone 模型“方法”上工作。你是对的,我的 bindAll 语法是错误的。谢谢!
    【解决方案2】:

    Peter Lyons 在这两点上都是正确的。您希望将每个函数作为参数传递给 bindAll,而不是传递函数数组。当使用 coffeescript 时,胖箭头是一种将函数绑定到定义它的上下文的好方法。

    我想回答为什么 _.bind 对你不起作用(因为我花了很长时间才弄明白)。答案是 _.bind 不会改变您传递的函数,它会使用提供的参数创建一个新函数。将其标记为createBoundFunction 会更合适。所以让 _.bind 在你的例子中工作就是:

    this.render = _.bind(this.render, this)
    this.foo = _.bind(this.foo, this) 
    

    此外,在单步阅读源代码时,我学到了很多关于如何绑定函数的知识,所以我希望您不要介意函数绑定的题外话,从咖啡脚本的作用开始。

    var __bind = function(fn, me){ return function(){return fn.apply(me, arguments); }; }
    

    CoffeeScript 将上述函数插入到每个使用粗箭头 (=>) 的文件中。这是老办法。它创建并返回一个新函数,该函数调用您的函数并应用您传递的上下文和参数。 CoffeeScript 然后为每个粗箭头定义的函数生成构造函数并调用 __bind。对于 Peter Lyon 的解决方案,生成的代码如下所示:

    this.render = __bind(this.render, this)
    this.foo = __bind(this.foo, this) 
    

    在我当前的项目中,我有 9 个使用粗箭头的视图,所以我定义了 9 次 __bind,这似乎违反了 DRY,但谁在乎,它是为我生成的。

    ECMAScript5 禁止函数原型上的新方法。

     Function.prototype.bind(thisArg [, arg1[, arg2[, ...]]])
    

    这种方法会使你的代码看起来像这样:

    this.render = this.render.bind(this)
    this.foo = this.foo.bind(this)
    

    不需要外部库或生成的方法。需要注意的是,这仅在最新+最好的浏览器(FF4、IE9、CH10>)中受支持,因此几年内无法单独使用它。

    下划线结合了这两个概念:

    _.bind = function(func, obj) {
      if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func,   slice.call(arguments, 1));
      var args = slice.call(arguments, 2);
      return function() {
        return func.apply(obj, args.concat(slice.call(arguments)));
      };
    };
    

    nativeBind 等于 Function.prototype.bind。因此,underscore 检查新的 ECMA5 绑定方法的可用性,如果不存在,则创建一个匿名函数,该函数使用您选择的上下文调用您的函数。

    如果我知道或可以找到有关 Function.prototype.bind 赋予的某些优势的信息,我会说避免使用 CS 胖箭头并使用 _.bind,特别是对于您的库中已包含下划线的主干项目,但我不知道它会带来优势,所以它可能并不重要。

    【讨论】:

      【解决方案3】:

      Backbone 现在允许您添加一个附加参数以将this 绑定到回调。见http://documentcloud.github.com/backbone/#FAQ-this。这样,您的视图方法将绑定到视图而不是集合。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-09-17
        • 2018-06-09
        • 2012-07-29
        • 1970-01-01
        • 2021-12-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多