Backbone和bindAll:“func未定义”

时间:2011-07-07 15:28:49

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

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

我试过了两次

  • bindAll(因上述错误而失败)和
  • 个人bind s(不工作)
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({})

3 个答案:

答案 0 :(得分:11)

答案 1 :(得分:8)

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个视图使用胖箭头,所以我有__bind定义了9次,这似乎违反了DRY,但是谁在乎,它是为我生成的。

ECMAScript5 禁止在Function原型上使用新方法。

 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。因此,下划线检查新ECMA5绑定方法的可用性,如果不存在,则创建一个匿名函数,使用您选择的上下文调用您的函数。

如果我知道或者可以找到有关Function.prototype.bind赋予的一些优点的信息,我会说要避免使用CS胖箭并使用_.bind,特别是对于已经包含在库中的下划线的骨干项目,但我不知道它会带来优势,所以它可能无论如何都无关紧要。

答案 2 :(得分:1)

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