众所周知,call
和apply
能够显式的指明一个方法中this
的指向,那假如,某一个方法需要频繁调用,而且其中的this
总是指向同一个对象,这时候每次都写fun.call()
或者fun.apply()
是不是有点太烦了—-所以,在这种情况下就可以使用bind
了。
首先要明白,bind
返回的是一个__新的函数__,这个新的函数中this
已经指明方向,如果再使用call
或者apply
来企图改变其中的this
指向,是没有效果的,看例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| var obj_01 = { name: "dasheng", age: 26 } var obj_02 = { name: "fansheng", age: 27 } var getName = function(){ console.log(this.name) } var getName_01 = getName.bind(obj_01); getName_01(); getName_01.call(obj_02);
|
bind()
方法的第一个参数为要绑定的this
指向,剩下的参数为预先传入函数中的参数,修改一下上面的例子:
1 2 3 4 5 6 7 8 9 10 11
| var obj_01 = { name: "dasheng", age: 26 }
var getName = function(age,work){ console.log(this.name+ " " + age + " " + work) } var getName_01 = getName.bind(obj_01,obj_01.age);
getName_01("程序员");
|
下面看一下bind
如何在旧浏览器中做兼容:
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
| 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(){}; var fBound = function(){ return fToBind.apply(this instanceof fNOP ? this :oThis || this, aArgs.concat(Array.prototype.slice.call(arguments))); }; fNOP.prototype = this.prototype; fBound.prototype = new fNOP(); return fBound; } }
if(Function.prototype.bind === undefined){ Function.prototype.bind = function(obj){ var fun = this; var args = Array.prototype.slice.call(arguments, 1); return function(){ var innerArgs = Array.prototype.slice.call(arguments); var allArgs = args.concat(innerArgs); fun.apply(obj, allArgs); } } }
|
两种版本里都用到了Array.prototype.slice.call()
,这种方法非常普遍的用来将类数组转成数组,看下它的源码实现:
1 2 3 4 5 6 7 8 9 10
| Array.prototype.slice = function(starti, endi){ var sub = []; for(var i = starti; i < endi; i++){ sub.push(this[i]); } return sub; }
|
bind()的一些用法
在默认情况下,使用window.setTimeout()
时,this
关键字会指向window
(或全局)对象。当使用类的方法时,要this
引用类的实例,这时候可能需要显式的把this
绑定到回调函数以便继续使用实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 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(this); console.log("I am a beautiful flower with" + this.petalCount + "petals!"); }
var flower = new LateBloomer(); flower.bloom();
|
另外bind()
还有一个常见的用法:有时候会将对象的某个方法拿出来单独使用,同时又希望方法中的this
指向原来的对象,这种情况下就需要使用bind()
来实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| this.x = 9; var module = { x: 81, getX: function(){ return this.x; } }
module.getX();
var retrieveX = module.getX; retrieveX();
var boundGetX = retrieveX.bind(module); boundGetX();
|
另外,还有一些关于bind()创造的函数的原型以及作为构造函数调用的问题,我暂时也不是很懂,不讲了。。。