• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

编写系列 实现 call apply bind

武飞扬头像
CodeSpirit
帮助26

大家好啊!这次我给大家带来的干货是如何自己实现call apply bind 这三个函数。

这三个函数大家应该都很熟悉,这三个函数是用于给普通函数进行this换绑的。

通过本文你能学到(复习)到什么知识📘

  1. 剩余参数(rest args)
  2. 普通函数和箭头函数的this指向。

我们先从Call入手📃

我们先从JS提供的Call来观察下,它的运行是什么样子的。

const obj = {
  a: "我的a",
};

function test(n1,n2) {
  console.log("这是哪里的a", this.a,n1 n2);
}
 
test.call(obj,10,20);

// 输出结果: 这是哪里的a 我的a 30

它接受一个this对象,原来的函数参数是通过追加的形式,一个个的加在call的函数内的。

那么我们要想要实现一个和这个差不多的功能,我们要怎么去做。

首先,call 是一个Function的实例方法,所以我们要实现和它一样的功能,也需要在Function的原型上添加对应的方法。

Function.prototype.callByHand=function(){}

1️⃣这样我们就实现了第一步,我们自己定义的函数也能调用callByHand了 ,恭喜恭喜🎇

2️⃣接下来,我们需要换绑this,那么我们就需要改变函数的执行上下文环境,如果大家对this的指向不是很明白,可以在评论区留言,我会在出文章专门介绍,这里暂时不赘述这部分内容。

Function.prototype.callByHand = function (bindThis) {
  let fn = this;
  bindThis.fn = fn;
  bindThis.fn();
};

这里简单说两句,定义callByHand的时候,一定要使用普通函数,因为普通函数的执行上下文是在函数执行的那一刻所决定的,和它定义的位置无关。

箭头函数不一样,它的执行上下文是由定义位置所决定的,身处在哪个作用域下面,它的this 也就指向哪个作用域。

所以我们看,在这里面,this 实际上就是指向调用callByHand的test函数,然后,我们给bindThis添加了一个fn属性,将我们的函数赋值给它,使用bindThis.fn()去执行的时候,test函数的执行上下文就是obj,那么我们在test函数内就能找到对应的a了,就是在obj中找到的。

3️⃣ 然后,我们来看下如何接受函数的参数呢?

这里就要用到剩余参数(restArg)了,因为这里并不确定函数到底有多少个入参,剩余参数呢能接受所有的入参转换为一个数组,它能够很好的满足我们的需求,所以我们接下来这么写。

Function.prototype.callByHand = function (bindThis, ...args) {
  let fn = this;
  bindThis.fn = fn;
  bindThis.fn(...args);
};

好,到此为止,你已经实现了call的基本功能了,这么看下来是不是实现很简单呢?

接下来介绍apply的实现📄

apply和call的区别仅仅在接受入参时有区别,apply是以数组形式接受函数的入参的
所以在实现方法上,没什么差异。

const test = function (n1, n2) {
  console.log("计算结果", this.a, n1   n2);
};

const obj = {
  a: 999,
};

Function.prototype.applyByHand = function (bindThis, args) {
  let fn = this;
  bindThis.fn = fn;
  bindThis.fn(...args);
};

test.apply(obj, [10, 20]); // 计算结果 999 30
test.applyByHand(obj, [10, 20]); // 计算结果 999 30

✔是不是很简单呢,看了之后,希望你能学会。

最后介绍bind的实现📑

bind的实现方式与前两者就不同了,call和apply在执行后,原函数就会被执行

但是bind并不会,他仅仅是绑定,而不执行函数。

因为不执行原函数,只是返回函数,所以我们在实现bind的时候,只要返回函数就行。

好,在我们知道这个思路后,我们来看下面代码,实际上也是差不多的形式。

const test = function (n1, n2) {
  console.log("计算结果", this.a, n1   n2);
};

const obj = {
  a: 999,
};

Function.prototype.bindByHand = function (bindThis, ...args) {
  const newFn = (...params) => {
    let fn = this;
    bindThis.fn = fn;
    if (args.length !== 0) bindThis.fn(...args);
    else bindThis.fn(...params);
  };

  return newFn;
};

const newFn = test.bind(obj, 30, 40);
newFn(10, 20);

const newFn2 = test.bindByHand(obj, 30, 40);
newFn2(10, 20);

注意点:我这里使用的箭头函数返回包装后的函数,是利用了箭头函数的this指向与执行时没有关系,所以它的this还是指向了obj

还有第二种解法,就是利用闭包,这样就拿到了对应的this指向,大家喜欢哪种解法就用哪种就行

Function.prototype.bindByHand = function (bindThis, ...args) {
  let fn = this;  
  const newFn = (...params) => {	  
    bindThis.fn = fn;
    if (args.length !== 0) bindThis.fn(...args);
    else bindThis.fn(...params);
  };

  return newFn;
};

因为bind函数可以传入参也可以不传,所以我稍微判断了下。优先级是bind函数的入参优先级最高。

💯💯💯恭喜你,看到这里你已经掌握call apply bind的手写啦,真棒啊~~~

最后哦,call apply bind的一些异常参数判断,我没有写,这个就作为大家的额外作业了,学会基础写法之后,相信你们在这基础上加异常判断也是易如反掌

PS:像如果传递的this是null或者undefined,apply入参是数组,传入基础类型怎么办。

最后再和大家打个招呼,我是CodeSpirit,可以叫我雪碧,是一名在前端路上学习的菜鸡,关注我,带你一起学习前端的知识

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfgafab
系列文章
更多 icon
同类精品
更多 icon
继续加载