call、apply、bind的區別

call()apply()bind()方法的做用都是改變函數運行時this的指向。 bind() 是返回對應的函數,便於稍後調用;call()apply()則是當即調用。數組

相同點app

  1. 都是用來改變函數執行時this的指向,即函數運行時的上下文;
  2. 第一個參數都是this要指向的對象;
  3. 均可以利用後續參數傳參。

一、apply、call

兩者做用徹底相同,只是接收參數上的不一樣。若是不傳入第一個參數,則默認上下文是 window函數

1)call
語法
  • fun.call(context, arg1,arg2...)
  • context: 在fun函數中運行時指定的this值
  • arg1,arg2:指定的參數列表
實現原理
Function.prototype.myCall = function(context, ...args) {
    if( typeof this !== 'function') {
        throw new TypeError('Error') // 判斷是不是函數調用
    }
    context = context ? Object(context) : window // 原始值的this會指向該原始值的實例對象 所以須要Object轉換成對象類型
    context.fn = this // 函數的this指向隱式綁定到context上
    const result = context.fn(...args) // 經過隱式綁定函數並傳遞參數
    delete context.fn // 刪除上下文對象的屬性
    return result // 返回函數執行結果
}

示例this

let test = {
    name: "test"
}
let  fun = {
    fn: function () {
          console.log(this.name)
    }
}
fun.fn.myCall(test) // test
2)apply
語法
  • fun.apply(context, [argsArr])
  • context:在fun 函數運行時指定的this值
  • argsArr:一個數組或者是類數組對象,其中數組中元素會做爲單獨參數傳給fun。當參數值爲null 或者undefined時,表示不須要傳入任何參數。
注意: 上述指定的this值(thisArg)並不必定是該函數執行時真正的this值,若是該函數處於 非嚴格模式下,則指定爲null或者undefined時會自動指向全局對象(瀏覽中就是window對象),同時值爲原始值(number、string、boolean)的this會指向該原始值的自動包裝對象。
實現原理
Function.prototype.myApply = function(context) {
    if( typeof this !== 'function' ) {
        throw new TypeError('Error')
    }
    context = context ? Object(context) : window
    context.fn = this
    let result
    if(arguments[1]) { // 處理參數上和call有區別
        result = context.fn(...arguments[1])
    } else {
        result = context.fn()
    }
    
    delete context.fn
    return result
}

示例prototype

function fn() {
    console.log(this.age)
}

let person = {
    age: 12
}
fn.myApply(person) // 12

二、bind

bind方法會建立一個新函數,稱爲綁定函數,當調用這個綁定函數時,綁定函數會以建立它時傳入bind()的第一個參數做爲this,傳入bind方法的 其餘參數以及和綁定函數運行時自己的參數 ,將按照順序做爲原函數的參數來調用原函數。code

語法
  • fun.bind(context, arg1, arg2, ...)
  • context:當綁定函數被調用時,該參數會做爲原函數運行時的this指向;當使用new操做符調用綁定函數時,該參數無效。
  • arg1,arg2...:綁定函數被調用時,這些參數將位於實參以前傳遞給綁定的方法。
實現原理
Function.prototype.myBind = function(context) {
    if( typeof this  !== 'function' ) {
        throw new TypeError('Error')
    }
    
    let args = [...arguments].slice(1) // bind 函數中的參數
    let self = this // 保存原函數
    return function() {
        return self.apply(context, args.concat(...arguments)) // arguments 是外部函數傳入的
    }
}

示例對象

let obj = {
    a: 'a'
};

function f(b, c, d) {
    console.log(this.a, b, c, d)
}

f.myBind(obj, 'b')('e') // a b e undefined
f.myBind(obj, 'b', 'c')('e') // a b c e
f.myBind(obj, 'b', 'c', 'd')('e') //a b c d
相關文章
相關標籤/搜索