1. 程式人生 > 實用技巧 >手動實現call、apply和bind

手動實現call、apply和bind

如果沒有傳參,那麼this預設指向的window

let a = {
    value: 1
}

function parent(sex, weight) {
    this.name = '1'
    this.age = 12
    this.sex = sex ? sex : null
    this.weight = weight ? weight : null
    console.log(123)
}

call的實現 call接受引數的方式 call(obj, params1, params2, ....)

Function.prototype.myCall = function
(context) { let currentObj = context ? context : window // 這裡就是傳入的第一個引數 currentObj.fn = this // 將parent函式存起來,parent呼叫的myCall,此時this指向的就是該方法 let arg = [...arguments].slice(1) // 將引數中除了第一個之後的全部存起來,第一個就是上下文要用的這個物件 console.log(...arg) currentObj.fn(...arg) // 將引數傳入,此時呼叫fn的是currentObj 即為傳入的物件a,所以parent中的this會指向a
delete context.fn // 將函式刪除 }
// 測試程式碼
// parent.myCall(a, 'mingzi', 'nianling')
// console.log(a);

apply的實現 apply接受引數的方式 call(obj, [params1, params2, ....])

Function.prototype.myApply = function (context) {
    let currentObj = context ? context : window // 這裡就是傳入的第一個引數
    currentObj.fn = this // 將parent函式存起來,parent呼叫的myCall,此時this指向的就是該方法
console.log(arguments) // [{value: 1}, ['張三', '12']] if(arguments[1]) { currentObj.fn(...arguments[1]) } else { currentObj.fn() } delete currentObj.fn } // 測試程式碼 // parent.myApply(a, ['boy', '50']) // console.log(a)

bind()實現

// 實現bind()方法 呼叫bind()必須是一個函式   可以通過new修改this  new的優先順序最高 bind()可以將引數分兩次傳遞進來
Function.prototype.myBind = function (context) {
    if(typeof this !== "function") { // 如果不是函式則直接丟擲
        throw new TypeError('Error')
    }
    let self = this // 儲存this,即為parent
    let arg = [...arguments].slice(1) // 將引數中除了第一個之後的全部存起來
    // bind()返回的是一個函式,所以可以使用new,並且會修改this的指向
    return function F() {
        if(this instanceof F) { // 如果new執行此時即為true
            return new self(...arg, ...arguments) // 返回new parent(第一次傳遞的引數, 第二次傳遞的引數) =》  arguments是執行返回的函式時的引數
        }
        return self.apply(context, [...arg, ...arguments]) // 如果沒有執行new  那麼直接執行parent,通過apply會將this執行最初傳進來的物件a
    }
}

// 測試程式碼

let bindResult = parent.myBind(a, 'women')
let result = new bindResult('666')
console.log(result);