如此高频出现的面试题?你还不会吗?快来复习。bind/call/apply

76 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情

今年6月所在公司宣布部门解散了。我也开始找踏上找工作之旅。历时一个多月,斩获几份offer。因为疫情影响本身HC比较少。加上频繁跳槽。简历直接被很多公司拒绝。找工作的时间战线相对以前。也被拉长了很多。今年的互联网。已然看不到以往朝气蓬勃的样子。或许以后会一直很艰难、更艰难。我们要做好长期战争的准备。持续完善自己。不抱有侥幸心理。只拿实力来说话。

在面试过程中。发现对于bind、call、apply的考察还是非常频繁的。我们今天再来复习一遍。对于手写题目一定要做到融会贯通。烂熟于心。

bind

"bind"对比 "apply""call"的功能完全不相同

  • "bind"会创建一个新的函数
  • "bind"返回的新函数内部的this是被永久改变的
  • "bind"返回的新函数在执行时才会改变this指向
Function.prototype.myBind = function (vm, ...arg1) {
  const self = this
  return function (...arg2) {
    const arg = arg1.concat(arg2)
    return self.apply(self, arg)
  }
}

function add(a, b, c) {
  console.log(a, b, c)
}

const fn1 = add.myBind({ a: 1, b: 2 }, 1, 2)
console.log(fn1, fn1(3))

call 和 apply

  • "call""apply" 都是执行函数并改变本次执行函数内部的this上下文
  • "call""apply" 的第二个入参不同。"call" 从第二个参数开始一个一个传入参数。"apply" 第二个把所有入参变成数组或者类数组传入。

这里提到了类数组。常见的类数组有arguments,NodeList 等,类数组使用Array.isArray会返回false,可以通过 Array.prototype.slice.call将类数组转换为数组。

Function.prototype.myCall = function (context, ...args) {
  if (!context) context = globalThis
  if (typeof context !== 'object') context = new Object(context)
  const key = Symbol()
  context[key] = this
  const res = context[key](...args)
  delete context[key]
}

Function.prototype.myApply = function (context, args) {
  if (!context) context = globalThis
  if (typeof context !== 'object') context = new Object(context)
  const key = Symbol()
  context[key] = this
  const res = context[key](...args)
  delete context[key]
  return res
}

function test(a, b) {
  console.log(this, a, b)
}

test.myCall({ a: 1 }, 2, 6)
test.myApply({ a: 1 }, [1, 2])