call、apply、bind使用與內部實現

基本使用

call、apply、bind的核心功能都是改變函數的this指向,但彼此之間也有一些差異。數組

call

改變this指向且執行函數,額外參數以參數列表形式傳入app

let context = {
    name:'神祕的寶爺'
}

const myFn = function(age,height){
    console.log(this.name+':'+age+':'+height)
}

myFn.call(context,25,'180cm')  // 神祕的寶爺:25歲:180cm

複製代碼

apply

與call幾乎同樣改變this指向且執行函數,額外參數以數組形式傳入函數

let context = {
    name:'神祕的寶爺'
}

const myFn = function(age,height){
    console.log(this.name+':'+age+':'+height)
}

myFn.call(context,[25,'180cm'])  // 神祕的寶爺:25歲:180cm

複製代碼

bind

改變this指向,的函數,而是返回一個this被改變的function,參數以參數列表形式傳入ui

let context = {
    name:'神祕的寶爺'
}

const myFn = function(age,height){
    console.log(this.name+':'+age+':'+height)
}

let myFn2  = myFn.bind(context)

myFn2(25,'180cm') // 神祕的寶爺:25歲:180cm

複製代碼

手動實現call、apply、bind

要實現call、apply,咱們須要作兩件事,第一是獲取到被綁定的函數,第二就是把被綁定的函數追加到劫持替換的對象上,而後再調用追加後的函數,因爲js的this指向機制是指向調用者,因此這兩步實現起來彷佛比較容易this

咱們拿call來舉例:spa

//context就是傳入的替代this的對象
Function.prototype.myCall = function(context,...params){
    //當傳入的替換變量不是對象的時候賦值成null
    if(typeof context === "object"){
        context = context || window
    }else{
        context = null
    }
    
    let funcName = Symbol() //使用Symbol類型定義臨時方法名,避免context上的方法與臨時方法重名
    context[funcName] = this //獲取到調用的function
    context[funcName](...params)
    delete context[funcName]  //originFunction只是個臨時屬性,調用完畢後刪除它
}

let context = {
    name:'神祕的寶爺'
}

const myFn = function(age,height){
    console.log(this.name+':'+age+':'+height)
}

myFn.myCall(context,25,'180cm')  // 神祕的寶爺:25歲:180cm


複製代碼

實現了call以後,apply就基本實現了,只是傳參方式不同:prototype

//context就是傳入的替代this的對象
Function.prototype.myApply = function(context,params){
    //當傳入的替換變量不是對象的時候賦值成null
    if(typeof context === "object"){
        context = context || window
    }else{
        context = null
    }
    
    let funcName = Symbol() //使用Symbol類型定義臨時方法名,避免context上的方法與臨時方法重名
    context[funcName] = this //獲取到調用的function
    context[funcName](...params)
    delete context[funcName]  //originFunction只是個臨時屬性,調用完畢後刪除它
}

let context = {
    name:'神祕的寶爺'
}

const myFn = function(age,height){
    console.log(this.name+':'+age+':'+height)
}

myFn.myApply(context,[25,'180cm'])  // 神祕的寶爺:25歲:180cm


複製代碼

bind實現跟上兩個不太同樣,可是基於上面的實現也比較簡單了,由於bind不調用函數,因此咱們返回一個function內部執行myCall就好了code

Function.prototype.myBind = function(context){
    return (...params)=>{
        this.myCall(context,...params)
    }
}

let context = {
    name:'神祕的寶爺'
}

const myFn = function(age,height){
    console.log(this.name+':'+age+':'+height)
}

const myFn2 = myFn.myBind(context)  

myFn2(25,'180cm')   // 神祕的寶爺:25歲:180cm


複製代碼
相關文章
相關標籤/搜索