在JavaScript编程中有很多改变this的方法和方式,今天说的bind与众不同,像call、apply改变this指向的时候会直接执行。而bind则不是,话不多说,直接进入正题。
bind
bind是函数原型上的一个方法,作用是改变this指向并且返回一个函数等待被执行。
Function.prototype.bind()
bind()可以传入多个参数,第一个参数作为改变this的一个对象,后面的参数作为返回函数的形参。
然而传入的第一个参数不同的话,指向也不同,看代码
var value = 0;
var obj = {
value : 1,
}
function(name,age){
console.log(value);
console.log(name + " " + age);
}
var newShow = show.bind(obj,abc,18);
newShow(); //返回 1 abc 18
var newShow = show.bind(null,abc,18);
newShow(); //返回 0 abc 18
new newShow(); // 返回 undefined abc 18
由此我们可以看出,当第一个参数是对象的时候,改变this的指向指向对象,当第一个参数为null的时候,此时的this指向window,当我们用 new newShow() 产生一个对象实例的时候,无论第一个参数填的什么,this都是指向对象实例。
bind的运用环境
当我们在后面进行模块化开发的时候,代码量大的时候,最容易犯的错误就是变量污染全局了,我们可以选择单变量编程来防止这件事情的发生。代码如下:
var obj = {
init : fucntion(){
},
bindEvent : function(){
},
show : function(){
}
}
这种方式就是模块化编程,当我们在对象函数中写进东西的时候,我们想让这三个函数建立起来联系,想让他们每次的初始this指向这个对象。这是时候就用到bind了。
var obj = {
init : function(){
var btn = document.getElementById('btn');
},
bindEvent : function(){
btn.onclick = this.show.bind(this);
},
show : function(){
console.log(this);
}
} obj.init()
此时我们在这样调用的时候不会因为this指向的问题而 弄不清作用域是什么。
现在我们开始想着用原生的方法模拟一下这个bind。
bind的模拟实现
我们现在想一下这个bind需要什么。由上面可知,bind第一个参数不用,this所指向不同。而且返回的是一个新的函数。当函数有返回值的时候还需要返回值
Function.prototype.newBind = function(target){
var target = target || window;
return function(){
return this.apply(target);
}
}
我们还知道,在newBind方法调用的时候是可以用多个形参的。作为返回函数的参数,而新返回的函数也是可以传参的,由于参数个数的不同我们可以选择用arguments来确定参数,这时我们可以用 [].slice.call(grguments);这种方式把类数组切成数组
Function.prototype.newBind = function(target){
var target = target || window;
var self = this;
var args = [],slice.call(arguments,1);
return function(){
var _args = [].slice.call(arguments,0);
return self.apply(target,args.concat(_args));
}
}
当我们在原型链上编程的时候,避免不了用原型上的东西,此时我们bind的方法也是可以继承原型上的属性和方法的,这里是使用圣杯模式的一种思想实现
Function.prototype.newBind = function(target){
var target = target || window;
var self = this;
var args = [].slice.call(arguments,1);
var temp = function(){};
var F = function(){
var _args = [].slice.call(arguments,0);
return self.apply(this instanceof temp ? this : target , args.concat(_args));
}
temp.prototype = this.prototype;
F.prototype = new temp;
return F;
}
这样我们的bind方法就完全实现了。自己试着用原声的方法模拟一下bind的实现,也会加深对bind 的理解。