underscore的bindAll和bind到底是什么

这个话题首先得从apply开始说起。bindAll内部实现使用了bind,而bind的内部实现又使用了apply。所以明白apply是什么作为第一步是非常重要的!

利用apply来帮我们改变this

先来看个例子:

var some = function(){
	console.log(this+"is here!");
}
some();

当我们执行这段代码的时候,得到的结果是

[object window] is here!
所以我么可以简单的理解,这里的this就是window, 它在global的环境下,的确它就是window,那为了改变this,我们怎么办呢,这时候apply就登场了,它可以改变调用范围内this的内容,如:

var some = function(){
	console.log(this+"is here!");
}
some.apply("some");
执行后就会得到:

some is here!
看到apply帮我们改变了该范围内this的值,并且将this想要替换的值放在apply函数的第一个参数的位置,其后的参数继续是原来的函数的参数:

为什么需要bind?

首先也来看个例子:

function Person(name){
	this.name = name;
	this.greet = function(){
		console.log("hello everyone, I am " + this.name);
	};
}

var tom = new Person("Tom");
tom.greet();//成功打印<hello everyone, I am Tom>
上述代码可以很成功的执行,但如果我们做如下改变:

function Person(name){
	this.name = name;
	this.greet = function(){
		console.log("hello everyone, I am " + this.name);
	};
}
var tom = new Person("Tom");
var greet = tom.greet();
greet();//输出<hello everyone, I am undefined>
这里就不行了,原因在于上下文环境变了,以上代码相当于将本来是放在Person下的greet函数放到了全局下面执行,this得到的是window,而window没有name属性,所以只能输出undefined。同样如上可以使用apply来解决这个问题,如下:

function Person(name){
	this.name = name;
	this.greet = function(){
		console.log("hello everyone, I am " + this.name);
	};
}

var tom = new Person("Tom");
var greet = tom.greet();
greet.apply(tom);//输出<hello everyone, I am Tom>
这里将tom替换到this,肯定输出Tom了。其实bind也正是在干这件事情,它返回一个新的函数,这个新的函数拥有我们提供的上下文环境。来看一下bind方法的源代码:

return function(){
	return function.apply(obj,args.concat(slice.call(arguments)));
}
可见,bind内部使用了apply来实现。再来看看underscore的bindAll方法,

function Person(name){
	this.name = name;
	this.greet = function(){
		console.log("hello everyone, I am " + this.name);
	};
}
var tom = new Person("Tom");
_.bindAll(tom,"greet");
var greet = tom.greet();
greet();//输出<hello everyone, I am Tom>
我个人更喜欢_.bindAll的方法,它的意思是将greet函数的上下文环境this永远置为tom,所以在任何地方调用都不会出现undefined,书写起来也更方便。bind会返回一个函数需要接收,而_.bindAll并不需要,更方便。

bind和bindAll在Backbone还有一些区别,如在Backbone中:

var ProductView = Backbone.View.extend({
  initialize: function() {
    _.bind(this.render, this);
    this.model.bind('change', this.render);
  }
});
这段代码不会成功执行,因为this.render并没有接收改变新的值,仍然为原来的,正确的写法为:
var ProductView = Backbone.View.extend({
  initialize: function() {
    this.render=_.bind(this.render, this);
    this.model.bind('change', this.render);
    //或者this.model.bind('change',_.bind(this.render,this));
  }
});

如果不喜欢这种异步IO方式的同学,可能使用如下方法比较方便,我就是这种人!哈哈

var ProductView = Backbone.View.extend({
  initialize: function() {
    _.bindAll(this.render, this);
    this.model.bind('change', this.render);
  }
});
不知道讲清楚了没!应该吧~
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值