JavaScript 手写 call、apply、bind函数

105 阅读1分钟

「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。

call、apply、bind 区别

  • 共同点:改变this指向

  • 不同点:

    • apply 的传递的参数是数组
    • callbind 都是一个个传递
    • bind 返回的是一个函数 而 callapply 返回的是函数的调用
标题callapplybind
共同点改变this指向改变this指向改变this指向
参数传递按个传递传递数组按个传递
返回值函数的调用函数的调用函数

实现 call & apply

applycall的区别只是参数传递方式的不同,所以放在一起实现,会比较好理解

思路

  • 创建一个临时空对象
  • 生成一个唯一的key
  • ctx[key]赋值成调用函数
  • 执行调用函数,并保存结果
  • 删除执行函数
  • 返回函数调用的结果
const core = (ctx, args, _this) => {
    const obj = {}
    // 生成一个唯一key
    const key = Symbol() 
    // 将调用函数赋值
    ctx[key] = _this
    // 执行调用函数
    const res = ctx[key](...args) 
    // 删除调用函数
    delete ctx[key]
    // 返回调用函数的结果
    return res
}

// apply
Function.prototype.applyFn = function(ctx, args) {
    return core(ctx, args, this)
}

// call
Function.prototype.callFn = function(ctx, ...args) {
    return core(ctx, args, this)
}

实现 bind


Function.prototype.bindFn = function() {
    const fn = this
    // 获取要指向的对象
    const _this = arguments[0]
    // 获取调用时的参数
    const tempArgs = [].slice.call(arguments, 1)
    // 创建一个函数
    const F = function(){}
    F.prototype = fn.prototype
    // 返回一个函数
    const retFn = function () {
        // 获取返回后的函数,传入的参数
        const retArgs = [].slice.call(arguments)
        // 执行原本的函数, 如果返回的函数被 new 就要忽略绑定的
        return fn.apply(fn instanceof F ? fn : _this, tempArgs.concat(retArgs))
    }
    retFn = new F()
    return refFn
}