js系列之實現call, apply, bind函數

bind 和 call/apply 同樣,都是用來改變上下文 this 指向的,不一樣的是,call/apply 是直接使用在函數上,而 bind 綁定 this 後返回一個函數(閉包) call和apply的惟一區別是call的除了第一個參數是綁定上下文,能夠傳多個參數,apply的第一個參數是綁定上下文,第二個參數是一個數組 calljavascript

Function.prototype.myCall = function(context) {
    // 處理第一個參數傳null或者undfined,這時將上下文綁定到window對象上
    context = context || window;
    context._fn = this;
    let args = [...arguments].slice(1);
    let result = context._fn(...args);
    delete context._fn;
    return result;
}
複製代碼

applyjava

Function.prototype.myApply = function(context) {
    context = context || window;
    context._fn = this;
    let args = [...arguments].slice(1); // 第二個參數是數組
    let result = context._fn(...args);
    delete context._fn;
    return result;
}
複製代碼

bind數組

  1. 函數調用,改變this
  2. 返回一個綁定this的函數
  3. 接收多個參數
  4. 支持柯里化形式傳參 fn(1)(2)
Function.prototype.myBind = function(context) {
    let self = this;
    let args = [...arguments].slice(1);
    return function() {
        let newArgs = [...arguments];
        return self.apply(context, args.concat(newArgs))
    }
}
複製代碼

可是做爲構造函數試用的時候會出錯,構造函數的this綁定在實例上,除此以外,還須要解決原型丟失的問題閉包

Function.prototype.myBind = function(context) {
    let self = this;
    let args = [...arguments].slice(1);
    var bound = function() {
        let newArgs = [...arguments];
        // 做爲構造函數使用
        if(this instanceof bound) {
            return self.apply(this, args.concat(newArgs))
        } else {
            return self.apply(context, args.concat(newArgs))
        }
    }
    // 維護原型關係
    if(this.prototype) {
        bound.prototype = this.prototype;
    }
    return bound;
}
複製代碼
相關文章
相關標籤/搜索