bind,call,apply模擬實現
首先,三者第一個參數都為this指向
區別
bind返回的是一個函數體
call和apply會直接執行,但是call參數需要一個一個進行傳遞,apply的第二個參數是一個數組
實現
bind
簡單實現
Function.prototype.myBind = function(context){ self = this; //保存this,即調用bind方法的目標函數 return function(){ return self.applay(context, [...arguments]); }; };
考慮到函數柯里化的實現
Function.prototype.myBind = function(context){ // 使用閉包存下初始參數 var args = Array.prototype.slice.call(arguments, 1), self = this; return function() { // 再次調用時 var innerArgs = Array.prototype.slice.call(arguments); var finalArgs = args.concat(innerArgs); return self.apply(context,finalArgs); }; };
考慮構造函數的實現
Function.prototype.myBind = function(context){ // 判斷是否為函數 if(typeof this !== 'function') { throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); } var args = Array.prototype.slice(arguments, 1); self = this; bound = function() { var innerArgs = Array.prototype.slice.call(arguments); var finalArgs = args.concat(innerArgs); // 判斷this,如果是,則傳遞this即實例化的對象。 return self.apply((this instanceof F ? this : context), finalArgs); }; // 處理原型鏈 let F = function(){}; F.prototype = self.prototype; bound.prototype = new F(); retrun bound; };
call
思路
// 要實現這個效果 var foo ={ value:1 } function bar(){ console.log(this.value) } bar.call(foo);//1 // 相當於做如下事情 var foo = { value: 1, bar: function() { console.log(this.value) } }; foo.bar(); // 1
實現
Function.Prototype.myCall = function(context) { // this 參數可以傳 null,當為 null 的時候,視為指向 window var context = context || window; context.fn = this; // 對參數進行處理 var args = []; for(var i = 1, len = arguments.length; i < len; i++) { args.push(arguments[i]); } let result = arguments.length>0 ? context.fn(...args) : context.fn(); delete context.fn; return result; }
apply
Function.Prototype.myApply = function(context, arr) { // this 參數可以傳 null,當為 null 的時候,視為指向 window var context = context || window; context.fn = this; let result = arr.length>0 ? context.fn(...arr) : context.fn(); delete context.fn; return result; }
參考自
MDN中對bind的實現