今天看到公司大神的一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | function ReplaceProcessor() {
this ._dom = {
btnReplace : $( '#ro_btnReplace' ),
btnComplete: $( '#ro_btnComplete' )
};
this ._dom.btnReplace.on( 'click' , this ._onReplace.bind( this ));
this ._dom.btnComplete.on( 'click' , this ._onComplete.bind( this ));
}
ReplaceProcessor.prototype._onReplace = function (){
this ._dom.btnComplete.html( "OK" );
}
|
这里面最后两行代码是向DOM节点上绑定事件,"this._onReplace.bind(this)"明显就是绑定的执行函数,在不知道具体作用的情
况下猜测一下bind()的作用可能和call或者apply类似,用来改变function执行时的上下文环境,不知道理解的对不对所以找资料来印证一
下。
先上官网的解释,不管我们个人的解释是多么的接地气,官方API到底还是比较靠谱的:
bind方法会创建一个新函数,称为绑定函数.当调用这个绑定函数时,绑定函数会以创建它时传入bind方法的第一个参数作为this,传入bind方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数.
这
个解释多读几次还是很靠谱的,不是很难懂。从功能描述上看和call以及apply还是有区别的,应用的场景不太一样,bind主要是为了改变函数内部的
this指向,这个是在ECMA5以后加入的,所以IE8一下的浏览器不支持,当然有兼容的办法,不过坦白说首先对于IE8以下实在无爱,其次那种情况下
估计你也没什么心情用bind了吧。。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if ( typeof this !== "function" ) {
throw new TypeError( "Function.prototype.bind - what is trying to be bound is not callable" );
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this ,
fNOP = function () {},
fBound = function () {
return fToBind.apply( this instanceof fNOP && oThis ? this : oThis || window,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this .prototype;
fBound.prototype = new fNOP();
return fBound;
};}
|
东
西就是这么个东西,最主要的还是应用的场景,什么情况下使用。本文一开始代码中使用.bind(this)的效果就相当于将事件绑定的callback抽
出来写,但是同时还维持了函数中的this指向。本来事件绑定的处理函数一般是一个匿名函数,这里相当于单独抽出来从而使结构更清晰的同时,this指向
的是ReplaceProcessor的实例。
这里列举三部分的代码来说明bind能为我们做些什么,同时它的好处在哪里。
(一)事件处理函数
所谓的事件处理函数其实就是绑定事件后的那个callback,这里如果用上bind你的代码应该会简洁优雅一些,我在开篇列出的那段代码里就是这样做的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | var logger = {
x: 0,
updateCount: function (){
this .x++;
console.log( this .x);
}
}
document.querySelector( 'button' ).addEventListener( 'click' , function (){
logger.updateCount();
});
document.querySelector( 'button' ).addEventListener( 'click' , logger.updateCount.bind(logger));
|
如何,这就是我之前说的,本来通常情况下处理函数都要用一层匿名函数包裹一下,才能维持处理函数本身的this.这里直接通过.bind(logger)人为的将其执行时的this指向logger对象。
.bind()创建了一个函数,当这个函数在被调用的时候,它的 this 关键词会被设置成被传入的值(这里指调用bind()时传入的参数)。
(二)setTimeout
1 2 3 4 5 6 7 8 9 10 11 12 | function LateBloomer() {
this .petalCount = Math.ceil( Math.random() * 12 ) + 1;
}
LateBloomer.prototype.bloom = function () {
window.setTimeout( this .declare.bind( this ), 1000 );
};
LateBloomer.prototype.declare = function () {
console.log( 'I am a beautiful flower with ' + this .petalCount + ' petals!' );
};
|
看一下这里this.dclare.bind(this),相当于将LateBloomer的实例对象传递到declare中,是不是setTimeout简洁了很多,同时不会破坏其他执行函数的结构。
(三)请完整阅读下面的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
var context = { foo: "bar" };
function returnFoo () {
return this .foo;
}
returnFoo();
var bound = returnFoo.bind(context);
bound();
returnFoo.call(context);
returnFoo.apply(context);
context.returnFoo = returnFoo;
context.returnFoo();
[1,2,3].slice(0,1);
var slice = Array.prototype.slice;
slice(0, 1);
slice([1,2,3], 0, 1);
slice.call([1,2,3], 0, 1);
slice.apply([1,2,3], [0,1]);
slice = Function.prototype.call.bind(Array.prototype.slice);
slice([1,2,3], 0, 1);
var bind = Function.prototype.call.bind(Function.prototype.bind);
var context = { foo: "bar" };
function returnFoo () {
return this .foo;
}
var amazing = bind(returnFoo, context);
amazing();
|
最后第三部分的代码来自一段译文:https:///posts/2013-10-22-bind-call-and-apply-in-javascript.html,代码很好所以忍不住拿来用,十分感谢.
补充一段代码,关于Ajax的回调中,如何保持this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | $.ajax({
url: url,
type: 'post' ,
dataType: 'json' ,
data: { 'info' : info}
})
.done(( function (data) {
if (data.status){
this ._data.process_type = info.process_type;
} else {
uUnique.noticeBox.showWarning(data.message);
}
}).bind( this ));
|
OK,感觉说到这里bind是做什么的应该么可以理解了
|