问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

手撕代码!一起来实现一个bind函数吧!

发布网友 发布时间:2024-10-08 16:45

我来回答

1个回答

热心网友 时间:2024-11-20 11:52

前言

this关键词可以说在JavaScript有着举足轻重的地位了!我们对它简直是又爱又恨,它在给我们带来简便快乐的同时,还给我们带来了痛苦,因为它的多变性,让我们开发人员经常不知道this到底指向的哪里,当然这有一部分是太菜的原因,另外一部分原因是this指向还是比较复杂的。

为了完全控制this指向,也就是我们常说的this指向的显示绑定,我们可以使用bind方法来显示绑定this。

1.bind函数用法

bind()方法用于创建一个新的函数,这个新函数接收的第一个参数代表的就是this,利用bind()函数我就就可以任意改变函数内部的this指向了。

官网的解释:

bind()方法创建一个新的函数,在bind()被调用时,这个新函数的this被指定为bind()的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

官网解释得也比较通透明了,我们这儿为了让大家更加深刻理解bind的用法,利用代码来演示一下。

示例代码:

<script>letobj={name:"小猪课堂",age:20}//声明一个函数functionfn(a,b,c){console.log("函数内部this指向:",this);console.log("参数列表:",a,b,c);}//使用bind创建一个新函数letnewFn=fn.bind(obj,10,20,30);//调用新函数newFn();//调用旧函数fn(10,20,30);</script>

输出结果:

上段代码中我们声明了一个函数fn,并且在函数内部打印了this以及参数,然后我们利用bind()创建了一个新的函数,且第一个参数传入了obj,意味着新函数内部的this指向了obj。分别执行两个函数,两个函数内部的this指向一个指向了全局,一个指向了window。

2.bind函数的特点

如果我们想要手动实现一个bind函数,那么非常有必要了解bind函数的特点,所以知己知彼方能百战不殆。

从上一节中的代码我们大致总结出了bind函数的以下几个特点:

2.1返回一个新函数

bind函数实际上是对原函数的一个拷贝,原函数认可以按照原逻辑处理。

示例代码:

<script>letobj={name:"小猪课堂",age:20}//声明一个函数functionfn(a,b,c){console.log("函数内部this指向:",this);console.log("参数列表:",a,b,c);}//使用bind创建一个新函数letnewFn=fn.bind(obj,10,20,30);console.log(typeofnewFn);//'function'</script>2.2新函数仍可继续传参

bind函数创建的新函数是可以接收参数的,之前的列子中我们是在创建的时候就将参数传递了进去,实际上可以不必传。

示例代码:

<script>letobj={name:"小猪课堂",age:20}//声明一个函数functionfn(a,b,c){console.log("函数内部this指向:",this);console.log("参数列表:",a,b,c);}letnewFn=fn.bind(obj,10);newFn(20,30);</script>

输出结果:

上面的输出结果和我们直接在创建的时候传递所有参数得出的结果一致,而且上段代码中我们的参数是分开传递的,也就是说使用bind创建新函数后,调用新函数时,函数接收的参数是调用传入的参数+创建时传入的参数。

2.3新函数作为构造函数

如果我们将使用bind创建的新函数当作构造函数来执行,那么this的指向将和bind创建时绑定的无关,它会指向一个新的引用。

示例代码:

<script>letobj={name:"小猪课堂",age:20}functionfn(name){this.name=name;console.log("函数内部this指向:",this);}letnewFn=fn.bind(obj);letobj2=newnewFn("构造函数");</script>

输出结果:

上段代码中我们使用bind新创建了一个函数newFn,而且将这个函数的this指向了obj,但是我们后续使用的时候使用了new关键词来创建,这个时候函数内部的this指向不在指向obj了,而是指向了fn。

那么既然this指向了fn,那么我们在fn原型上添加属性或方法后,obj2是能访问到的。

3.实现bind函数

既然我们知道了bind的几个特点,那么我们遵循它的即可特点就可以来实现它了。

首先它是返回一个新函数,我们可以先把架子搭起来,代码如下:

Function.prototype.myBind=function(){//返回新函数returnfunction(){//代码先省略}}

上段代码只是一个基本的架子,我们在里面填充代码就好了。接下来我们需要将函数的this指向为传进来的第一个参数,并且使用bind创建的新函数可以继续接收参数,代码如下:

<script>letobj={name:"小猪课堂",age:20}//手写bind函数Function.prototype.myBind=function(context){const_this=this;//当前函数letargs=Array.from(arguments).slice(1);//将参数列表转化为数组,出去第一个参数外//返回新函数returnfunction(){//context是传进来的this_this.apply(context,args.concat(Array.from(arguments)));//利用apply将this指向context,参数进行拼接}}//声明一个函数functionfn(a,b,c){console.log("函数内部this指向:",this);console.log("参数列表:",a,b,c);}letnewFn=fn.myBind(obj,10,20);newFn(30);</script>

上段代码中需要注意的有两点,第一点是利用apply函数将函数的this指向了传进来的context,第二点是将参数新传进来的参数与args拼接,因为我们调用newFn时,可能传进来新参数,所以需要将新老参数拼接上。

输出结果:

上面的输出结果是和直接使用bind函数输出的结果是一样的。上面的代码还不够完善,如果我们将创建的新函数以构造函数的方式执行的话,this的执行和原生的bind不太一致。

代码如下:

<script>letobj={name:"小猪课堂",age:20}//手写bind函数Function.prototype.myBind=function(context){const_this=this;//当前函数letargs=Array.from(arguments).slice(1);//将参数列表转化为数组,除去第一个参数外//返回新函数returnfunction(){//context是传进来的this_this.apply(context,args.concat(Array.from(arguments)));//利用apply将this指向context,参数进行拼接}}//声明一个函数functionfn(a,b,c){console.log("函数内部this指向:",this);console.log("参数列表:",a,b,c);}letnewFn=fn.myBind(obj,10,20);//调用封装的bindletnewFn1=fn.bind(obj,10,20);//调用原生的bindnewnewFn("myBind构造函数");newnewFn1("bind构造函数");</script>

输出结果:

上面的输出结果不一致,说明使用原生bind创建的新函数,如果使用构造函数的方式执行,那么函数内部的this执行会作为一个新的引用指向fn。

修改代码如下:

<script>letobj={name:"小猪课堂",age:20}//手写bind函数Function.prototype.myBind=function(context){const_this=this;//当前函数letargs=Array.from(arguments).slice(1);//将参数列表转化为数组,除去第一个参数外//返回新函数letfn=function(){//如果被new调用,this应该是fn的实例return_this.apply(thisinstanceoffn?this:(context||window),args.concat(Array.from(arguments)))}//维护fn的原型lettemp=function(){}temp.prototype=_this.prototype;fn.prototype=newtemp();//new的过程继承temp原型returnfn};//声明一个函数functionfn(a,b,c){console.log("函数内部this指向:",this);console.log("参数列表:",a,b,c);}letnewFn=fn.myBind(obj,10,20);letnewFn1=fn.bind(obj,10,20)newnewFn("myBind构造函数");newnewFn1("bind构造函数");</script>

输出结果:

上段代码的输出结果是不是就和实际的bind函数输出结果一样了啊!想要理解上段代码,大家有必要去学习以下JS中new一个对象发生了什么,主要是下面几步:

创建一个新对象

将构造函数的this赋值给新对象

执行构造函数代码,给这个新的对象添加属性

返回新的对象

具体的new实现过程还需要大家自己去理解。

总结

想要实现bind函数,就必须要理解其中的原理,无非就是改变this指向的问题。其中唯一的难点就是如何实现构造函数执行的方式,也就是要明白js中new一个对象的时候发生了什么?

如果觉得文章太繁琐或者没看懂,可以观看视频:?小猪课堂

原文:https://juejin.cn/post/7101851473679974413
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
陕西职务侵占案立案准则 结婚后我的恋情维系了十年,怎么做到的? 玉米仁子饭产自哪里 中国期货交易所的交易品种有哪些? 历史要怎么读,有啥诀窍 高中历史诀窍 年终会活动策划方案 深度解析:第一财经回放,探索财经新风向 逆水寒手游庄园怎么邀请好友同住 逆水寒手游 逆水寒不同区可以一起组队吗? 电信签手机签约,停机有什么后果? 诛仙前传死亡沼泽瘟皇.秦广是什么怪 ...求高手给我说说显卡的好坏,以及最近笔记本的主流显卡。 造纸术是谁发明的?东汉的哪位发明家改造了造纸术?他做了哪些改造?_百 ... 诛仙2中死亡沼泽有哪些爆东西多的怪 如何分辨GT显卡好坏 gt显卡怎么看好坏? ...纸是我国古代的四大发明之一, 你知道下列哪位人物 我国是四大文明古国之一,造纸术是我国的四大发明之一。 哪一位同学能... gt笔记本显卡是怎么分级别haphuaidw 全国法律硕士联考法律硕士(非法学)和法律硕士(法学)有什么区别?_百度... 法律硕士(非法学)1月联考全日制和半脱产是分开录取还是一起录取之后分... 那里能找到不用注册就能免费的交谊舞曲 请大师看一下生辰八字婚姻 男兔 1987年 阴历10月25 ,早上5 点55. 女... 当烦恼无法忘记怎么办? 怎样忘记烦恼和不喜欢的事情? ...9月4日下午2点多生的男孩想测一下自己的生辰八字如何,事业如何,爱情... 日本“纳豆荞麦面”与“纳豆汽水”开箱 这口味也太奇葩了! 你见过哪些奇葩饮料? 脊髓损伤导致下半身无知觉,如何才能康复,去看医生要多少钱 你知道什么是call、apply、bind? 计算机ip地址的分配方法 iPhone5屏幕边角泛红过一会儿就恢复正常泛红地方消失了 Iphone5在今天使用过程中突然关机然后开不开机,强制开机就花屏关机,刷 ... ...那位好心人能帮帮我……走头无路啦!!谢谢…… 现在好心人多吗?哪个大哥.大姐愿意帮我一把呀.我走头无路了.做人太难... 好心人我走投无路 我现在流浪在外面今天找一个工作月底上班饿几天 求... 微信公众号中国反邪教如何关注签名呢? 真的走投无路了 死了不划算了 有人愿意帮我吗.以后一辈子不管任何事情随... 高考完了想去俄罗斯留学 现在还可以申请吗 这个世界好心人太少.走投无路我想借钱还被别人说是幼稚骗子.没人帮我... 去俄罗斯留学 高考后找中介办理时间够吗 ...高考后打算去那里留学,有没有比较好的留学机构推荐? 出国俄罗斯留学条件 如何不想自己喜欢的人? 一首英文歌 歌词有一句是 我祈求上帝 不要让我退色太快 O型腿的注意事项 纯净水可以喝多久 纯净水安全饮用时间 o形腿的注意事项 打扫名言