在JavaScript中,函数中this的指向每每在调用时才可肯定,而JavaScript提供了call/apply/bind方法让咱们得以显示绑定函数的this指向。
它们的第一个参数是一个对象,它们会把这个对象绑定到调用他们的函数内的this。由于你能够直接指定 this 的绑定对象,所以咱们称之为显式绑定。windows
//用例 var a = { q: 1 }; var b = { q: 2 }; var c = { q: 3 }; function cs(s) { console.log(this.q) } cs.bind(a)();//1 cs.call(b);//2 cs.apply(c);//3
var s = new fn.myBind({ a: 2333 })();//报错!!,运算优先级:属性访问>带参new>函数调用>无参new var s = new (fn.myBind({ a: 2333 }))();//正确姿式
参数从arguments[1]开始,func.myCall(obj:Object[,agr1:any[,agr2:any[...]]])数组
if (!Function.prototype.myCall) { Function.prototype.myCall = function (targetThis) { //targetThis默认为windows(严格模式不容许) targetThis = targetThis || window; //利用对象调用指定this targetThis.fn = this; //收集参数 var agrs = []; //由于arguments[0]===targetThis,故从下标1开始 for (var ge = 1, len = arguments.length; ge < len; ge++) { agrs.push('arguments[' + ge + ']'); } //利用eval展开参数 并执行函数 var result = eval('targetThis.fn(' + agrs + ')'); //删除附加对象的属性以消除反作用 delete targetThis.fn; //返回结果 return result; } }
参数放在数组里func.call(obj:Object[,agr:Array])app
if (!Function.prototype.myApply) { Function.prototype.myApply = function (targetThis, arrAgrs) { //targetThis默认为windows(严格模式不容许) targetThis = targetThis || window; //利用对象调用指定this targetThis.fn = this; var agrs = []; //收集参数数组 for (var ge = 0, len = arrAgrs.length; ge < len; ge++) { agrs.push('arrAgrs[' + ge + ']'); } //利用eval展开参数 并执行函数 var result = eval(' targetThis.fn(' + agrs + ')'); //删除附加对象的属性以消除反作用 delete targetThis.fn; //返回结果 return result; } }
参数从arguments[1]开始,func.myCall(obj:Object[,agr1:any[,agr2:any[...]]])函数
//考虑参数合并以及new优先级和原型继承 if (!Function.prototype.myBind) { Function.prototype.myBind = function (targetThis) { //若非函数对象来调用本方法,报异常 if (typeof this !== "function") { throw new TypeError( "Function.prototype.bind error" ); } //收集参数 var bindArgs = Array.prototype.slice.call(arguments, 1), originFunction = this,//保存原始this(原始函数) fnProto = function () { },//利用空函数间接连接prototype以应对new时的原型继承 fnBounding = function () { //考核new操做this绑定优先 return originFunction.apply( ( this instanceof fnProto ? this : targetThis ), bindArgs.concat( Array.prototype.slice.call(arguments) ) ) }; fnProto.prototype = this.prototype;//连接原型 //new一个fnProto以实现简洁继承原型,防止对fnBounding.prototype的操做污染originFunction原型prototype fnBounding.prototype = new fnProto(); return fnBounding; }; }
bind以后能够再bind或call/applythis
if (!Function.prototype.softBind) { Function.prototype.softBind = function (obj) { var fn = this; // 捕获全部 bindArgs 参数 var bindArgs = [].slice.call(arguments, 1); var fnBounding = function () { return fn.apply( (!this || this === (window || global)) ? obj : this, curried.concat.apply(bindArgs , arguments) ); }; fnBounding .prototype = Object.create(fn.prototype);//连接原型 return fnBounding ; }; }