天天看點

帶你一起實作call函數call回顧實作思路實作結束語

昨天搞完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指向,它還可以實作繼承。比如當你寫一個函數,然後讓另外一個新的函數去繼承它。這樣就不用在新函數中寫重複代碼了。

實作思路

實作前,需要實作的關鍵問題如下:

  1. 了解call從哪裡來?要寫在哪裡?
  2. 如何修改this指向?
  3. 如何傳遞參數?
  4. 傳入undefined情況怎麼解決?

解決思路如下(注:與問題條目一一對應):

  1. javaScript函數都是Function構造函數的執行個體,是以yourfunction.call(),中的call一定來自于Function.prototype,是以我們隻需要将自己要寫的myCall挂載到Function原型上即可。
  2. 這裡我們需要給目标對象建立一個新的屬性,來承載被調用函數的引用位址。然後借用this的隐式綁定,就講函數挂在到了新對象上。(不懂得小夥伴,看下面具體實作部分就懂了哈)
  3. arguments是一個函數内,對應傳遞給函數的參數的類數組對象。我們将它直接解構給待執行函數即可。
  4. 我們這裡直接當做非嚴格模式即可,當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)
           

結束語