JS前端面试手写apply和bind实例

前言

面试官问:“聊一聊你理解的 applybind。”

于是我便开始开始介绍起这两个知识点,最后顺带提了它们的实现代码。

这不提倒还好,一提就出了大事,一下子给面试官找到了面试题目。

面试官紧接着说:“既然你提到了代码,那就手写一下它俩吧。”

我一下子不知所措。虽然我了解过 applybind 手写代码,但是现在让我立马手写出来它们,实属有些困难。

不过最后还是硬着头皮写了一下,但是结果不尽人意。

apply && bind

函数 applybind 在日常开发中经常会被用到,理解它们的作用以及逻辑至关重要。所以今天我们来探讨一下它们的实现逻辑,并对它们进行手写,来学会如何轻松手写它们。

apply && bind 作用

知己知彼,方能百战百胜。在进行手写之前,我们先来简单聊一下它们。 众所周知,apply 和 bind 作用是改变函数的调用对象。很多人对这个不是很理解,什么是函数的调用对象呢?其实简单点理解就是改变函数的 this 对象指向。因为这时候 this 在函数就充当了一个调用的作用,而 apply 和 bind 就是有着改变 this 指向的作用。

apply 的其他作用,是改变对象的执行上下文,并且是立即执行的。 bind 也能改变对象的执行上下文。

相同点 VS 不同点

它们的相同点在于都可以改变 this 的指向,并且传入的第一个参数都是绑定的 this,不同点在于 bind 返回的是一个改变了 this 指向的函数,便于稍后调用,而 apply 会立即调用。另外 apply 是一次性传入参数,而 bind 可以分为多次传入。

轻松手写

有了理论基础,我们可以开始手写部分了。

手写实现 apply

我们先来看 applyapply 手写实现其实很简单,大致思路如下:

首先用 typeof 来检查调用 apply 的对象是否为函数,如果不是则抛出错误。然后将函数作为传入的 context 对象的一个属性,并调用该函数。 最后调用之后通过 delete 删除该属性,避免对传入对象造成污染。context 代表上下文对象。

代码如下:

Function.prototype.apply = function (context, args) {
  if (typeof this !== 'function') {
    console.log('not a function')
  }
  const fn = Symbol()
  context[fn] = this
  context[fn](...args)
  delete context[fn]
}

这里使用到了新的 Symbol 数据类型,主要是避免在把函数赋值给 context 对象的时候,因为属性名冲突而覆盖掉原有属性。

手写实现 bind

相比较与 apply 手写,我个人觉得 bind 手写会相对复杂一些。bind 手写实现思路如下:

和之前一样,首先判断调用对象是否为函数,然后获取其余传入参数值,并创建一个函数返回。最后根据调用方式,传入不同的绑定值。

函数内部使用 apply 来绑定函数调用,需要判断函数作为构造函数的情况,这个时候需要传入当前函数的 thisapply 调用,其余情况都传入指定的上下文对象 context

代码如下:

Function.prototype.myBind = function(context) {
  if (typeof this !== "function") {
    console.log("Error");
  }
  let args = [...arguments].slice(1),
  fn = this;
  return function Fn() {
    return fn.apply(
      this instanceof Fn ? this : context,  
      args.concat(...arguments)
    );
  };
};

总结

关于它们的手写就到这里了,相信下次再面对同样的问题时处理起来就能游刃有余了。这两个手写各有各的特点,我个人建议可以多写写 bind 的手写,我觉得它会比 apply 出错率更高。

虽然文章中是以手写 apply 和 bind 为主,但是并不缺少 js 相关知识点,比如 this 指向问题,总之,js 很重要,既是基础又是重点。

作者:一条会coding的Shark

%s 个评论

要回复文章请先登录注册