在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 ; }; }