将一组名称传递给_.bindAll - 参数列表的类型错误

时间:2014-12-29 23:04:38

标签: javascript backbone.js underscore.js

我们在Backbone Views中使用常见模式。我们有类似的事件对象:

var TokenInputBaseView = Backbone.View.extend({

  events: {
    'click .remove-token' : 'click_removeToken',
    'mousedown .add-token': 'click_addToken',
    'keydown input'       : 'keydown_input',
    'click input'         : 'click_input',
    'focus .token-input'  : 'focus_input',
    'blur .token-input'   : 'blur_input',
  },

几乎在每种情况下,我们都希望所有事件处理程序都绑定到View,而不是它们的事件对象。所以我们这样做:

initialize: function(){
  _.bindAll(this, 'click_removeToken', ...);
}

我们必须手动列出每个事件名称。如果我们可以简单地传入一个数组,那将是理想的,但是下划线不能实现这个用途:

_.bindAll(this, _.values(this.events));

Underscore希望将各个名称作为参数而不是数组传入。但是,这也不起作用:

_.bindAll.apply(this, _.values(this.events).unshift(this));

Javascript出现此错误:

"Uncaught TypeError: Function.prototype.apply: Arguments list has wrong type"

有关简化bindAll使用的好方法的任何想法,以便它不需要手动列出要绑定的所有函数名吗?

1 个答案:

答案 0 :(得分:3)

您正在传递bindAll unshift的返回值,这是修改后的数组的长度。您需要存储数组引用,修改它,然后将该引用传递给apply或使用其他一些技巧:

// note, no need to bind to `this`
_.bindAll.apply(null, [this].concat(_.values(this.events)));

一个简短的例子:

var target = document.querySelector('#target');

var map = {
  'foo': 'foo',
  'bar': 'bar'
};

function C() {
  this.value = 'Value';
  _.bindAll.apply(null, [this].concat(_.values(map)));
}

C.prototype.foo = function() {
  console.log('hello', this);
  target.textContent = this.value + ' set by foo';
}

C.prototype.bar = function() {
  return this.value;
}

var c = new C();

document.addEventListener('click', c.foo);
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>

<div id="target">Click me</div>