昨天搞完this指向後,我們順藤摸瓜來,一起來實作個call方法吧。call、apply、bind中之是以選擇call,首先,它簡單些。其次,bind的實作需要借助call、apply。最後,就是我個人最常用call。那就讓我們開始吧。
call回顧
具體實作前,我們需要回顧一下call的使用方法。相信隻有真正掌握了怎麼用的人,才更容易把它實作出來。
文法上,call函數接收可供選擇的this值,以及不計數量的參數清單。例如:.call(thisArg, arg1, arg2, ...)。又或者,.call(undefined, arg1, arg2, ...)。
功能上,call提供新的this值給目前被調用的函數或者方法。當然,call為新this提供的函數、方法的來源可以是其他對象的函數方法。
使用上,處理修改this指向,它還可以實作繼承。比如當你寫一個函數,然後讓另外一個新的函數去繼承它。這樣就不用在新函數中寫重複代碼了。
實作思路
實作前,需要實作的關鍵問題如下:
- 了解call從哪裡來?要寫在哪裡?
- 如何修改this指向?
- 如何傳遞參數?
- 傳入undefined情況怎麼解決?
解決思路如下(注:與問題條目一一對應):
- javaScript函數都是Function構造函數的執行個體,是以yourfunction.call(),中的call一定來自于Function.prototype,是以我們隻需要将自己要寫的myCall挂載到Function原型上即可。
- 這裡我們需要給目标對象建立一個新的屬性,來承載被調用函數的引用位址。然後借用this的隐式綁定,就講函數挂在到了新對象上。(不懂得小夥伴,看下面具體實作部分就懂了哈)
- arguments是一個函數内,對應傳遞給函數的參數的類數組對象。我們将它直接解構給待執行函數即可。
- 我們這裡直接當做非嚴格模式即可,當this為空時,指派稱為window。
實作
let name = '今晚打老虎';
function yourFunction(x, y) {
console.log(this.name, x + y);
}
const YaoShen = {
name: 'YaoShen'
}
Function.prototype.myCall = function(obj, ...arg) {
obj.temFunc = this;
const result = obj.temFunc(...arg); //這裡感興趣的同學 可以考慮下相容性
delete obj.temFunc;
return result;
}
yourFunction.myCall(YaoShen, 1, 2)