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

作者&投稿:不枯 (若有异议请与网页底部的电邮联系)
~ 前言

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


撕码是什么意思?
撕码(Shred Code)是指将源代码或二进制代码彻底摧毁的过程,其目的是为了保护个人隐私或避免代码泄露。撕码可以将代码彻底删除,不留任何痕迹,极大地增强了数据安全性。撕码应用广泛,尤其对于那些需要保护知识产权的企业是非常重要的。例如IT安全公司中对于源码的安全保密、司法机关中嫌疑人电脑硬盘数据的...

今天我在语文课上写程序代码,然后被语文老师看见了,一下来就想没收,我...
撕都撕了,还能咋的!劝你不要采取过激的暴力手段,到此为止吧,他是有错,但谁叫你上语文课做别的事呢,而且还和他对抗,所以只能是扯平了,以后注意点就是了,这次就怨自己倒霉吧

如何委婉地提醒一个人安静地敲代码?
毕竟敲代码肯定会有声音,其实人家只要不停止用电脑,声音是不可能有多安静的,你委婉的说还不如直接说,这样我想她明白了你的意思,如果不是很要紧的话,估计会为你考虑不敲代码,休息一会的,或者如果是白天,她可以换一个地方敲代码,这样也不会影响到你。

字节代码没撕出来
提前准备。关于手撕代码,公司不同,要求不同,但是有一点是很显然的,那就是即使你写不出来可运行的代码,也得有清晰的思路,绝大部分公司则要求写出完整的代码,而代码能力和基础知识不同,不是短时间能够恶补的,更不是可以死记硬背的(当然了基础知识也要理解),需要日积月累,所以要提前准备。

如何编写一些一段网页代码做玩笑网站,追加(最好有代码)
alert("那好,我再来一个!") alert("从前") alert("有一个小孩牵个羊") alert("我的故事就这么长") alert("你不愿意听是吗?") alert("那怎么办?") alert("你已经出不去了") alert("还是关掉电脑来的干脆") alert("试试吧") alert("还是...

车辆识别代号被4s店维修店撕了
还需4s店维修。工作人员撕下来可能也会在加上去,不用担心,如在检查时没有标志的话,可以再去找下相关工作人员帮忙处理。车辆识别代码,VIN是英文VehicleIdentificationNumber的缩写。因为ASE标准规定:VIN码由17位字符组成,所以俗称十七位码。正确解读VIN码,对于我们正确地识别车型,以致进行正确地诊断和...

...上网找他们都是说出招代码,看不懂,有谁可以告诉我一下
暗咆哮 (1) ← A\/C 蚀天羽 →↓→ A\/B\/C 逆剃爪 ↓← A ← A → A 朔夜颚 ←↓← A\/B\/C ↓ A → A �1�7\\螺旋 (投)→← ↓→ C 深渊腕 ↓→↓← B 光腕(2) ↓→↓← C 死蚀破片 (2) ← ↓→ C 漆�1�7\\翼 ↓←↓→ C...

2017年7月1号以后给部队开普通发票纳税人号没有怎么办?
给军队部队开具增值税发票的纳税人识别号是:000011000000000如果没有组织机构代码证或者无税务登记证,就根据增值税普通发票开具的规则来:前四位是“0”,第5、6位是特殊行业的两位特定编码。纳税人识别号原则上是无含义代码。对于取得技术监督局9位组织机构代码的纳税人,其纳税人识别号采用6位行政区划...

小鹏“撕”特斯拉霸凌,破局的关键点是这个
在不久前的一篇文章中,我就有提到了2020年是L3级别自动驾驶量产的元年,其实L3级别自动驾驶并不是终点,只是一个过渡阶段。早在2018年,小鹏 汽车 创始人何小鹏就有提到,希望在2022年实现L4级别的自动驾驶,并将L4自动驾驶与特定场景联系起来。在上个月22日,小鹏P7上市之前,何小鹏就在微博上称,“...

在GMS2中使用Surfaces实现屏幕撕裂\/波纹效果
作者:nikles 翻译: highway★ 原文地址: 在GMS2中使用Surfaces实现屏幕撕裂 \/ 波纹效果 初衷 在玩过 Environmental Station Alpha之后,我也想实现Hempuli(上句那个游戏的开发者)在他的游戏做出的效果。我不知道该如何实现,所以只能从头开始,思考不同的方法。我对shader(译注:着色器)一窍不通,...

北票市13255577364: socket编程的bind函数问题 -
暴连贝特: 服务器端程序 /******* 服务器程序 (server.c) ************/ #include #include #include #include #include #include #include #include int main(int argc, char *argv[]) {int sockfd,new_fd;struct sockaddr_in server_addr;struct sockaddr_in client_addr;...

北票市13255577364: jQuery中bind函数用法
暴连贝特: 问题1: &lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt; &lt;html xmlns=" http://www.w3.org/1999/xhtml"&gt; &lt;head&gt; &lt;meta http-equiv="Content-...

北票市13255577364: 求解决一段js -
暴连贝特: 你好,你的写法没有将它们区分开.最简单的写法,是写2个函数.最好的写法,是用你这种写法写一个通用的函数,但是相对麻烦,代码如下:players();$("#b1,#b2").bind("click",funct...

北票市13255577364: js中call,apply和bind方法的区别和使用场景 -
暴连贝特: 在js中,所有的函数再被调用的时候都会默认传入两个参数,一个是this,还有一个是arguments.在默认情况下this都是指当前的调用函数的对象.但是有时候我们需要改变this的指向,也就是说使函数可以被其他对象来调用,那么我们应该怎样...

北票市13255577364: 怎样在一个BindView里添加一个点击事件
暴连贝特: 在你的bindview里放入如下代码就好了:public void bindView(View v, Context context, final Cursor c) {int tvGoto = c.getColumnIndexOrThrow("mColumn"); final String gotoLink = c.getString(tvGoto); TextView gotoTxt = (TextView) v.findViewById(...

北票市13255577364: Eval方法和Bind方法的区别? -
暴连贝特: Eval 方法是静态单向(只读)方法,所以Eval 函数用于单向(只读)绑定,该方法采用数据字段的值作为参数并将其作为字符串返回. Bind 方法支持读/写功能,所以Bind 函数用于双向(可更新)绑定.该方法可以检索数据绑定控件的值并将任何更改提交回数据库.

北票市13255577364: socket编程里关于bind的问题 -
暴连贝特: 你是在linux下么? linux下21号端口绑定需要root权限.检查下是什么错误:if(server_bind == -1) { perror("bind"); return 1; }

北票市13255577364: Java动态代理问题;求解 -
暴连贝特: jdk动态代理绑定的对象必须是一个接口申明的实现类,你可以看你public Object bind(Object obj)中的代码,在返回对象时有个参数是调用getInterface().获取接口,必须用接口去声明

北票市13255577364: js函数中 如何阻止事件冒泡 -
暴连贝特: function stopBubble(e){ 17. // 如果传入了事件对象,那么就是非ie浏览器 18. if(e&&e.stopPropagation){ 19. //因此它支持W3C的stopPropagation()方法 20. e.stopPropagation(); 21. }else{ 22. //否则我们使用ie的方法来取消事件冒泡 23. window.event.cancelBubble = true; 24. } 25. } 26.

北票市13255577364: Jquery中bind和live的区别 -
暴连贝特:Jquery中绑定事件有三种方法:以click事件为例(1)target.click(function(){});(2)target.bind("click",function(){});(3)target.live("click",function(){});第一种方法很好理解,其实就和普通JS的用法差不多,只是少了一个on而...

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网