JavaScript中,模擬 call 的底層實現

JavaScript中,模擬 call 的底層實現

面試題

function fn1 () {
   
   
    console.log(1)
}

function fn2 () {
   
   
    console.log(2)
}

// call 的作用
// 調用 call fn1函數,並改變fn1內部的this,將 this 指向 fn2
fn1.call(fn2)   // 1
fn1.call.call(fn2) // 2

模擬 call 的實現

沒有傳參

// 讓所有的函數對象,都具有 mycall 方法
// context.fn1()
Function.prototype.mycall = function mycall(context, ...args) {
   
   
    // context = context || window
    // ?? 
    // 只有 context 的值是 null 或者 undefined 的時候,纔會返回 window
    context = context ?? window
    // 此處的 this 指向的是 fn1 函數
    // 臨時把 this 存儲進 context.fn 中
    context.fn = this
    const result = context.fn(...args)

    delete context.fn
    return result
}

執行過程

// fn1.mycall.mycall(fn2),執行過程
Function.prototype.mycall = function mycall(context, ...args) {
   
   
	// context ---> fn2
    context = context ?? window
    // context.fn ---> this ---> mycall
    // fn2.mycall
    context.fn = this
    // 暫停,等待執行 fn2.mycall (沒有參數)
    const result = context.fn(...args)

    delete context.fn
    return result
}

// 調用 fn2.mycalll (沒傳參數)
Function.prototype.mycall = function mycall(context, ...args) {
   
   
	// context ---> Window
    context = context ?? window
    // context.fn ---> this ---> fn2
    // window.fn2
    context.fn = this
    // window.fn2 (沒有參數)
    const result = context.fn(...args)

    delete context.fn
    return result
}

傳入參數

// context.fn1()
Function.prototype.mycall = function mycall(context, ...args) {
   
   
    // 此處要去處理 context 是原始值的問題
    switch (typeof context) {
   
   
        case 'number':
            context = new Number(context)
            break
        case 'string':
            context = new String(context)
            break
        case 'boolean':
            context = new Boolean(context)
            break
        default:
            // context = context || window
            context = context ?? window
    }

            // 此處的 this 指向的是 fn1 函數
            // 臨時把 this 存儲進 context.fn 中
            context.fn = this
            const result = context.fn(...args)

            delete context.fn
            return result
    }

    const obj = {
   
    name: 'zs' }
    // fn1.mycall(obj)
    fn1.mycall.mycall(fn2, "1", 2)
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章