call, apply, bind的內部實現原理


call, apply, bind都是改變函數執行的上下文,說的直白點就是改變了函數this的指向。不同的是:call和apply改變了函數的this,並且執行了該函數,而bind是改變了函數的this,並返回一個函數,但不執行該函數。

看下面的例子1:

var doThu = function(a, b) {
    console.log(this)
    console.log(this.name)
    console.log([a, b])
}
var stu = {
    name: 'xiaoming',
    doThu: doThu,
}
stu.doThu(1, 2) // stu對象 xiaoming [1, 2]
doThu.call(stu, 1, 2) // stu對象 xiaoming [1, 2]

由此可見,在stu上添加一個屬性doThu,再執行這個函數,就將doThu的this指向了stu。而call的作用就與此相當,只不過call為stu添加了doThu方法后,執行了doThu,然后再將doThu這個方法從stu中刪除。

下面來看call函數的內部實現原理:

Function.prototype.call = function(thisArg, args) {
    // this指向調用call的對象
    if (typeof this !== 'function') { // 調用call的若不是函數則報錯
        throw new TypeError('Error')
    }
    thisArg = thisArg || window
    thisArg.fn = this   // 將調用call函數的對象添加到thisArg的屬性中
    const result = thisArg.fn(...[...arguments].slice(1)) // 執行該屬性
    delete thisArg.fn   // 刪除該屬性
    return result
}

apply的實現原理和call一樣,只不過是傳入的參數不同而已。下面只給出代碼,不做解釋:

Function.prototype.apply = function(thisArg, args) {
    if (typeof this !== 'function') { 
        throw new TypeError('Error')
    }
    thisArg = thisArg || window
    thisArg.fn = this
    let result
    if(args) {
        result = thisArg.fn(...args)
    } else {
        result = thisArg.fn()
    }
    delete thisArg.fn
    return result
}

bind的實現原理比call和apply要復雜一些,bind中需要考慮一些復雜的邊界條件。bind后的函數會返回一個函數,而這個函數也可能被用來實例化:

Function.prototype.bind = function(thisArg) {
    if(typeof this !== 'function'){
        throw new TypeError(this + 'must be a function');
    }
    // 存儲函數本身
    const _this  = this;
    // 去除thisArg的其他參數 轉成數組
    const args = [...arguments].slice(1)
    // 返回一個函數
    const bound = function() {
        // 可能返回了一個構造函數,我們可以 new F(),所以需要判斷
        if (this instanceof bound) {
            return new _this(...args, ...arguments)
        }
        // apply修改this指向,把兩個函數的參數合並傳給thisArg函數,並執行thisArg函數,返回執行結果
        return _this.apply(thisArg, args.concat(...arguments))
    }
    return bound
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM