bind、call、apply 的原理解析

bind、call、apply 三者的作用

都是用來改變函數運行時的 this 指向問題

基本使用

var name = 'window'

function test() {
    console.log(...arguments)
    console.log(this.name)
    return 'test function'
}

console.log(test(1, 2, 3))
console.log(test.bind({ name: 'bind'}, 1, 2, 3)(4, 5))
console.log(test.call({ name: 'call'}, 1, 2, 3))
console.log(test.apply({ name: 'apply'}, [1, 2, 3]))

> 1, 2, 3
> window
> test function
> 1, 2, 3, 4, 5
> bind
> test function
> 1, 2, 3
> call
> test function
> 1, 2, 3
> apply
> test function

使用 bind 在修改源函數的情況

重復綁定無效
只會生效第一次的綁定

var name = 'window'

function test() {
    console.log(...arguments)
    console.log(this.name)
    return 'test function'
}

test = test.bind({ name: 'bind'}, 1, 2, 3)
test = test.bind({ name: 'bind1'}, 4, 5, 6)
console.log(test(7, 8))

// result
> 1, 2, 3, 4, 5, 6, 7, 8
> bind
> test function

bind、call、apply 三者的區(qū)別

bind call apply
參數 (目標對象,query1, query2,..) (目標對象,query1, query2,..) (目標對象,[query1, query2,..])
返回值 已經將 this 硬綁定為目標對象的一個函數,再次調用這個返回函數之后,才能執(zhí)行原函數并得到原函數的返回值 原函數的返回值 原函數的返回值

原理實現

bind

Function.prototype.lBind = function (target) {
    // 截取傳進來的除目標對象之外的其余參數
    var _argu = Array.prototype.slice.call(arguments, 1)
    var _this = this

    return function () {
        // 接收新的參數
        _argu = _argu.concat(Array.prototype.slice.call(arguments))

        Object.defineProperty(target, '_fn', {
            enumerable: false,  // 不可枚舉
            writable: false,    // 不可寫
            configurable: true, // 可以配置 才可以刪除
            value: _this
        })
        var result = target._fn(..._argu)

        delete target._fn

        return result
    }
}

console.log(test.lBind({ name: 'lBind' }, 1, 2, 3)(4, 5))
test = test.lBind({ name: 'lBind' }, 1, 2, 3)
test = test.lBind({ name: 'lBind' }, 4, 5, 6)
console.log(test(7, 8))

// result
> 1, 2, 3, 4, 5
> lBind
> test function
> 1, 2, 3, 4, 5, 6, 7, 8
> lBind
> test function

call

Function.prototype.lCall = function (target) {
    // 截取傳進來的除目標對象之外的其余參數
    var _argu = []
    for (var i in arguments) {
        if (i !== '0') _argu.push(arguments[i])
    }
    var _this = this

    Object.defineProperty(target, '_fn', {
        enumerable: false,  // 不可枚舉
        writable: false,    // 不可寫
        configurable: true, // 可以配置 才可以刪除
        value: _this
    })
    var result = target._fn(..._argu)

    delete target._fn

    return result
}

console.log(test.lCall({ name: 'lCall'}, 1, 2, 3))

// result
> 1, 2, 3
> lCall
> test function

apply

Function.prototype.lApply = function (target) {
    // 截取傳進來的除目標對象之外的其余參數
    var _argu = arguments[1] || []
    var _this = this

    Object.defineProperty(target, '_fn', {
        enumerable: false,  // 不可枚舉
        writable: false,    // 不可寫
        configurable: true, // 可以配置 才可以刪除
        value: _this
    })
    var result = target._fn(..._argu)

    delete target._fn

    return result
}

console.log(test.lApply({ name: 'lApply'}, [1, 2, 3]))

// result
> 1, 2, 3
> lApply
> test function

【筆記不易,如對您有幫助,請點贊,謝謝】

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容