1. 程式人生 > 其它 >手寫 call、apply、bind

手寫 call、apply、bind

手寫 call、apply、bind

JavaScript 中 call()、apply()、bind() 的用法

ES6 實現,參考 awesome-coding-js

模擬實現 call
/*
foo.call(db, fm, t) 的結果可以理解為 
1. db 物件呼叫了 foo 函式;
2. fm 和 t 引數也傳到 foo 函式裡去了

那麼我們要實現 call,就要做到以上兩點
第一點:
但是問題是 db 物件本身沒有 foo 函式啊,怎麼解決呢?
解決方案就是把 foo 函式傳到 db 物件裡面成為 db 物件的方法,然後就可以實現 db.foo 了,直接執行就可以了
第二點
我們需要把引數傳進去 foo 函式,利用 ES6 的 ...args 就可以實現
*/
Function.prototype.myCall = function (context = Window, ...args) { if (this === Function.prototype) { return undefined // 防止 Function.prototype.myCall() 直接呼叫 } // 這裡還可以優化,如果傳進來的是 null,undefined,字串,該咋整 context = context || Window // 儲存傳進來的物件,this 就是要繫結給它的 const fn = Symbol() // 確保不會重名
context[fn] = this // 儲存要被呼叫的函式到物件中 const result = context[fn](...args) // 將引數傳進去呼叫 delete context[fn] // 刪除 fn 屬性 return result } // 測試 var foo = function (fm, t) { console.log(this.name + " 年齡 " + this.age, " 來自" + fm + '去往' + t) } var db = { name: '德瑪', age:
99 } foo.call(db, '成都', '上海') // 德瑪年齡99 來自成都去往上海 foo.myCall(db, '成都', '上海') // 德瑪年齡99 來自成都去往上海
模擬實現 apply
Function.prototype.myApply = function (context = Window, args) {
    if (this === Function.prototype) {
        return undefined // 防止 Function.prototype.myApply() 直接呼叫
    }
    context = context || Window // 儲存傳進來的物件,this 就是要繫結給它的
    const fn = Symbol() // 確保不會重名
    context[fn] = this // 儲存要被呼叫的函式到物件中
    let result
    if (Array.isArray(args)) {
        result = context[fn](...args)
    } else {
        result = context[fn]()
    }
    delete context[fn] // 刪除 fn 屬性
    return result
}

// 測試 myApply
foo.apply(db, ['成都', '上海']) // 德瑪年齡99  來自成都去往上海
foo.myApply(db, ['成都', '上海']) // 德瑪年齡99  來自成都去往上海
模擬實現 bind
/*
foo.bind(target) 返回的是一個函式物件(閉包),foo.bind(target)() 這樣子才會執行
*/
Function.prototype.myBind = function (context = Window, ...args1) {
    if (this === Function.prototype) {
        throw new TypeError('Error')
    }
    
    const _this = this
    // 這裡的 F 相當於 foo.bind(db, fm, t)() 的 foo.bind(db, fm, t)
    return F = function (...args2) {
        // 這裡可以優化,暫時不理解,先放著
        return _this.call(context, ...args1.concat(...args2)) // 用 call 實現 foo.bind(db, fm, t)()
    }
}

// 測試 myBind
foo.bind(db, '成都', '上海')() // 德瑪年齡99  來自成都去往上海
foo.myBind(db, '成都', '上海')() // 德瑪年齡99  來自成都去往上海

`

ES5實現,參考 [位元組大佬lhytGithub`](https://github.com/lhyt/issue/issues/14)

暫未實現,後續將更新…