Backbone中bind和bindAll的作用

本文参考:
http://blog.bigbinary.com/2011/08/18/understanding-bind-and-bindall-in-backbone.html

bindAll内部调用了bind(),而bind()又内部调用了apply()

apply()的作用

apply lets us control the value of this when the function is invoked.
apply可以改变函数function的上下文,也就是this的值

例子:

var func = function beautiful(){
  alert(this + ' is beautiful'); //这里的this是全局变量 window
};
func();
var func = function beautiful(){
  alert(this + ' is beautiful');
};
func.apply('Internet');// 修改this的值

为什么要改变this的值

因为js的变态,举个栗子

function Developer(skill) {
  this.skill = skill;
  this.says = function(){
    alert(this.skill + ' rocks!');
  }
}
var john = new Developer('Ruby'); //实例化一个Developer
john.says(); //调用says()方法 Ruby rocks!

在这种情况下 this是Developer对象。
但是,如果换下面的写法,就不是了。

function Developer(skill) {
  this.skill = skill;
  this.says = function(){
    alert(this.skill + ' rocks!');
  }
}
var john = new Developer('Ruby');
var func = john.says;
func();// undefined rocks!

在这种情况下,func()是在全局上下文调用的,所以this就变成了全局变量window,window.skill因为没有定义,所以是undefined。

使用apply来修改:

function Developer(skill) {
  this.skill = skill;
  this.says = function(){
    alert(this.skill + ' rocks!');
  }
}
var john = new Developer('Ruby');
var func = john.says;
func.apply(john);

这种方式虽然解决了问题,但是每次调用时,都要传递“john”这个参数,不方便函数的调用。

In JavaScript world functions are first class citizens. The reason why we create function is so that we can easily pass it around. In the above case we created a function called func. However along with the function func now we need to keep passing john around. That is not a good thing. Secondly the responsibility of rightly invoking this function has been shifted from the function creator to the function consumer. That’s not a good API.

因此,我们需要使用bind。

使用bind来解决

function Developer(skill) {
  this.skill = skill;
  this.says = function(){
    alert(this.skill + ' rocks!');
  }
}
var john = new Developer('Ruby');
var func = _.bind(john.says, john); //bind有返回值,返回一个函数
func();// Ruby rocks!

To solve the problem regarding this issue we need a function that is already mapped to john so that we do not need to keep carrying john around. That’s precisely what bind does. It returns a new function and this new function has this bound to the value that we provide.

bind的内部实现:

return function() {
  return func.apply(obj, args.concat(slice.call(arguments)));
};

bind(方法名, this上下文)

bind并没有修改原来的方法,而是返回一个新方法,这个新方法的this已经变成了第二个参数中赋予的值。

使用bindAll来解决

function Developer(skill) {
  this.skill = skill;
  this.says = function(){
    alert(this.skill + ' rocks!');
  }
}
var john = new Developer('Ruby');
_.bindAll(john, 'says');
var func = john.says;
func();

在使用bind时,必须使用bind返回的函数。

在使用bindAll时,不必考虑返回值。实质上,bindAll是改变了原来定义的函数。

在原来定义的Developer类中,有一个'says'属性,bindAll直接改变了'says'属性。

使用Backbone的常见错误

错误代码:

window.ProductView = Backbone.View.extend({
  initialize: function() {
    _.bind(this.render, this);
    this.model.bind('change', this.render);
  }
});

错误原因:bind的返回值没有被使用,所以_.bind(this.render, this);没有起作用

修改:

window.ProductView = Backbone.View.extend({
  initialize: function() {
    var func = _.bind(this.render, this);
    this.model.bind('change', func);
    //或者
    // this.model.bind('change', _.bind(this.render, this));
  }
});

或者使用bindAll

window.ProductView = Backbone.View.extend({
  initialize: function() {
    _.bindAll(this, this.render);
    this.model.bind('change', this.render);
  }
});

posted @ 2018-02-09 13:51  生活总得有些仪式感  阅读(701)  评论(0编辑  收藏  举报