关于apply,bind,call

13 阅读1分钟

什么是apply,bind,call

这三个都是可以显式绑定this的

区别

特性是否立即执行参数传递方式返回值
apply数组传参:fn.apply(thisArg, [arg1, arg2, ...])函数执行结果
bind逐个传参(或部分预设):fn.bind(thisArg, arg1, arg2, ...)新函数 (永久绑定this)
call逐个传参:fn.call(thisArg, arg1, arg2, ...)函数执行结果

详细用法

  1. apply
function introduce(age, city) {
  console.log(`I'm ${this.name}, ${age} years old, from ${city}.`)
}

const user = { name: 'Bob' }
introduce.apply(user, [25, 'Paris'])
// 输出: I'm Bob, 25 years old, from Paris.
  1. bind
function say(message) {
  console.log(`${message}, ${this.name}!`)
}

const tom = { name: 'Tom' }
const sayToTom = say.bind(tom, 'Hi')

sayToTom() // 输出: Hi, Tom!

// 即使作为回调,this 仍被锁定
setTimeout(sayToTom, 1000) // 1秒后仍输出: Hi, Tom!
  1. call
function greet(greeting, punctuation) {
  console.log(`${greeting}, I'm ${this.name}${punctuation}`)
}

const person = { name: 'Alice' }

greet.call(person, 'Hello', '!')
// 输出: Hello, I'm Alice!

手写

  1. 手写apply
function myApply(context, argsArray) {
  context = context || globalThis
  // 判断进来的示例是否为空,如果为空则绑定为全局
  context.fn = this
  // 因为这里是函数调用myApply 所以这里的this指的是函数
  const result = argsArray ? context.fn(...argsArray) : context.fn()
  // 传递参数并执行函数拿到执行结果
  delete context.fn // 删除fn,
  return result // 返回结果
}
// 测试代码
const obj = { name: 'zhangsan' }
function test(age, gender) {
  console.log(this.name, age, gender)
}
test.myApply = myApply
test.myApply(obj, [20, 'male']) // zhangsan 20 male
  1. 手写bind
Function.prototype.myBind = function (context, ...presetArgs) {
  const fn = this
  return function (...callArgs) {
    // 支持 new 调用(进阶)
    if (new.target) {
      return new fn(...presetArgs, ...callArgs)
    }
    return fn.apply(context, presetArgs.concat(callArgs))
  }
}
  1. 手写call
Function.prototype.myCall = function (context, ...args) {
  context = context || globalThis // 浏览器中是 window,Node 中是 global
  context.fn = this // 把函数挂到 context 上
  const result = context.fn(...args)
  delete context.fn // 清理
  return result
}