编写系列 实现 call apply bind
大家好啊!这次我给大家带来的干货是如何自己实现call apply bind 这三个函数。
这三个函数大家应该都很熟悉,这三个函数是用于给普通函数进行this换绑的。
通过本文你能学到(复习)到什么知识📘
- 剩余参数(rest args)
- 普通函数和箭头函数的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
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13