手寫一個bind函數(大概)

昨天搜了下bind怎麼實現,你們都在說bind的特徵啊啥的,沒搜到,今天有人問起來,我反問他要咋搜,他和我說柯里化。柯里化!!!它的最經常使用的表現形式不就是傳說中的閉包的其中一種嘛!!!segmentfault

I think! I can do it!!!我以爲我能夠嘗試着實現一下。閉包

apply的實現

首先咱們來回想this指向的幾種可能性:app

  1. 當函數做爲一個對象的屬性被調用時,‘.’ 前面是誰this就指向誰。如:obj.run()、obj.a.run(),run函數裏的this就分別指向obj和a。
  2. 當給dom元素綁定事件時,方法裏的this指向綁定的dom元素。如:app.onclick = function a(){},a裏的this這時候指向app。
  3. 構造函數裏的this指向它的實例。如:function A(){this.a = 1}; let b = new A(),這時A中的this就指向b。
  4. 以上都不是,this指向window,嚴格模式指向undefind。

想一想咱們能夠使用可能性1,先來寫個aplly方法:dom

先寫個實驗用具:函數

function sum(a, b) {
    return this.a + this.b
}
let obj1 = {
    a: 11,
    b: 7
}
let obj2 = {
    a: 1,
    b: 1,
}
複製代碼

再寫個第一版仿生myApply:post

function myApply(that, arg){ //接受that參數參數,做爲將來this
    that = JSON.parse(JSON.stringify(that)) //給作個深拷貝,不影響原來的對象
    that.Fn = this  //給對象設置屬性Fn,讓它等於咱們前面調用myApply的sum
    return that.Fn(...arg)  //用屬性調用的方式執行函數,讓this指向傳入的that,放入參數
}
複製代碼

但這麼寫有個問題,咱們但願在sum裏面對this進行操做的時候,做爲this源的對象也跟着改動,因此咱們那麼寫:測試

function myApply(that, arg = []){
    that = that!== null && typeof that === 'object'?that: {} //在this不爲object時的處理
    that.Fn = this
    const result = that.Fn(...arg)
    delete that.Fn //使用完以後對that下的Fn進行刪除
    return result
}
複製代碼

完成後咱們將myApply放到Function的原型上並測試看看它:ui

Function.prototype.myApply = myApply

console.log(sum1.myApply(obj1)) //18
console.log(sum2.myApply(null, [2, 3])) //5
複製代碼

到這裏apply方法就算寫完了。this

bind的實現

柯里化(curry):只傳遞給函數一部分參數來調用它,讓它返回一個函數去處理剩下的參數。spa

接下來咱們要用到柯里化形式的閉包來保存下bing函數調用時的this和傳進來的參數,以便在返回函數中用到它們:

function myBind(that, ...arg) { //建立時保存bind中傳進來的arg
    const _Fn = this    //保存sum函數
    return function () {
        const args = [...arg, ...arguments]   //合併兩次傳遞進來的參數
        return _Fn.myApply(that, args)  //調用sum函數的myApply方法
    }
}
複製代碼

和前面同樣,將myBind放到Function的原型上,並測試它:

Function.prototype.myBind = myBind

const sum3 = sum1.myBind(obj1)
console.log(sum3()) //18
const sum4 = sum1.myBind(obj1).myBind(obj2)
console.log(sum4()) //18

const sum5 = sum2.myBind(obj1, 5)
console.log(sum5(6)) //11
複製代碼

參考

相關文章
相關標籤/搜索