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);
}
});