You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
varmyObj={name: 'wan',sayHello: function(age){console.log('hello, my name is '+this.name+', I`m '+age+' years old');}}vartest={name: 'cheng'}myObj.sayHello(25);// hello, my name is wan, I`m 25 years old// 使用call和apply改变this指向myObj.sayHello.call(test,25);// hello, my name is cheng, I`m 25 years oldmyObj.sayHello.apply(test,[25]);// hello, my name is cheng, I`m 25 years old
Function.prototype.callOne=function(context){context.fn=this;context.fn();deletecontext.fn}myObj.sayHello.callOne(test,25);// hello, my name is cheng, I`m undefined years old
前言
大家都知道,
call, apply, bind
都是用来改变一个方法的this
指向的,只是参数和调用方式有区别而已,如果对这一块还不了解的可以自己查一下。那不知道大家想过没有,这几个方法内部是如何实现的呢,我们试着用原生js来实现一下。
call和apply方法到底做了什么
首先看一段代码:
查文档可知,
call
和apply
的语法分别是:经过观察可知,
call
和apply
的作用实际上就是在目标thisArg
里运行了一遍function
,然后将这个方法删除了。所以我们模拟实现一个自己的call
的思路可以是在目标上下文环境的thisArg
里 添加一个唯一属性,指向我们调用的方法,执行之后再删除。实现一个自己的call
先实现一个自己的
call
,callOne
,因为call
是function
原型对象上的一个方法,所以可以依据上面的思路重写一个自己的call
:第一个版本:
好,经过第一个版本,我们成功改变了
this
的指向,可是参数还没做处理,那下个版本就对参数处理一下吧。第二个版本:
特别注意一下,循环里面之所以要用
string
,是为了在eval
中最后再执行,不然参数传字符串时会有问题。第三个版本:
经过对参数的处理,好像差不多了呢,现在传多个不同类型的参数也是可以的了。那接下来据解决一下极端情况吧:
thisArg
这个参数时可以不传或者传null
的,这种情况下'thisArg'是指向window
的。context
中的fn
属性,并且还删除了,这是有隐患的,万一本来它就有这个属性那就修改了context
的值了,这肯定是不行的。所以我们可以自己造一个类似于ES6
中的symbol
类型的唯一属性作为context
的过渡属性。所以针对上面两个问题进行一下优化:
到这一步,对于
call
的模拟实现就基本完成了。实现一个自己的apply
apply
跟call
差不多,只是参数不同而已,所以唯一的区别就是对于参数的处理改变一下就行了。实现一个自己的bind
bind
与call
最大的区别就是不会立即运行,返回的是一个函数。参考
The text was updated successfully, but these errors were encountered: