js手写 apply(),call(),bind()

69 阅读1分钟

相信不少小伙伴在面试中,都会被问到怎么改变this的指向呢,然后你说:call、apply、bind

面试官:介绍一下这三者的区别

UP: 来来来,我给你手写一个

定义一个function

function fn(arg1, arg2, arg3) {

    console.log('fn被执行', this, arg1, arg2, arg3)  

    return arg1 + arg2 + arg3
}

call() 接收多个参数

//调用fn.Mycall() 隐式调用 this指向Mycall函数调用者 

// 接收 this 传参  剩余参数 rest parameters
// 展开运算符 arr = ['1','2','3']    ...arr  
Function.prototype.Mycall = function(thisArg, ...args) {

    //获取被执行的函数
    var fn = this

    //thisArg为传参进来的指定this   
    //这里考虑thisArg类型不确定问题以及thisArg为空或不传值的情况 使用Object()方法
    var thisArg = thisArg ? Object(thisArg) : window

    // 将需要被执行的函数绑定在指定的this上 
    thisArg.a = fn

    // 执行函数  并返回结果
    var result = thisArg.a(...args)

    console.log(thisArg, result) // Number {123, a: ƒ}  
    //因为给a等于一个函数 所以这里会多一个f 可以执行完删除 也可以不必理会
    //  delete thisArg.a
    
    return result
}
//fn 调用 Mycall() 


// var ccc = fn.Mycall(123, 3, 5, 7)
// console.log(ccc) //  15

apply() 接收一个数组

//数组入参
Function.prototype.Myapply = function(thisArg, argArray) {
    var fn = this

    // 考虑 thisArg  没有传参或者为空的情况
    var thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window

    thisArg.a = fn

    // 考虑 argArray  没有传参的情况
    argArray = argArray || []

    var result = thisArg.a(...argArray)

    return result

}
// var ccc = fn.Myapply('abc', [3, 5, 7])
// console.log(ccc) // 15

bind() 接收多个参数并返回一个新的函数

Function.prototype.Mybind = function(thisArg, ...argArray) {

    var fn = this // 要执行的函数
    var thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window

    //bind 生产一个新函数 
    function proxyFn(...args) {

        thisArg.a = fn

        var bindargs = [...argArray, ...args] // 或者concat

        console.log(bindargs) // [3, 5, 7, 1, 2]
        var result = thisArg.a(...bindargs)

        return result
    }
    return proxyFn //bind方法返回一个函数

}

// var ccc = fn.Mybind('bind', 3, 5, 7)
// ccc(1, 2)