前言
提到this指向改变方式,绕不过去的三座大山,call,apply,bind,没有广告,单纯记录下自己的手写过程,仅供参考.
call,apply,bind的区别
这篇文章总结的很全:call,apply,bind的区别
this对象+要调用的目标方法
- this对象
const zoeInfo={
name:"Zoe",
age:"27"
}
- 要调用的目标方法
const targetFunc=function(...role){
console.log([this.name,this.age,...role])
}
call的实现
- 根据mdn 对call的描述我们确定需求
- 支持多个参数,除了第一个参数this ,其余为目标函数的入参
- this改变指向后需立即执行
- 另外补充一点,this不传时候 默认指向window
2.思路
- 将目标函数设为目标对象(this)的属性
- 执行该函数
- 删除该函数
3.代码实现
Function.prototype.myCall=function(context){
//不传this时 避免报错,默认指向window对象
var context=context||window
//将函数设为对象的属性 ,有疑惑的小伙伴 可以在这里console下这里的this
context.fn=this
let arr=[]
//这里i从1开始,因为第一参数是this
for(let i=1;i<arguments.length;i++){
arr.push('arguments['+i+']')
}
//eval() 函数会将传入的字符串当做 JavaScript 代码进行执行。
const result=eval( 'context.fn('+arr+')')
//删除该函数
delete context.fn
//return执行该函数
return result
}
4.调用
targetFunc.myCall(zoeInfo,"前端菜🐔")
5.效果
bind的实现
- 根据mdn 对apply的描述我们确定需求
- 和call的区别是 第二参数得是一个数组
- 效果相同
- 思路
- 同 call 一样
3.代码实现
Function.prototype.myApply=function(context,arr=[]){
//不传this时 避免报错,默认指向window对象
var context=context||window
context.fn=this
//不传第二参数,直接调用 然后return
if(!arr.length){
context.fn()
delete context.fn
return
}
let args=[]
//和call有些些区别,arr 已经设置了默认值[],就是指向apply的第二参数
//i无需从1开始遍历
for(let i=0;i<arr.length;i++){
args.push('arr['+i+']')
}
const result=eval('context.fn('+args+')')
delete context.fn
return result
}
4.调用
targetFunc.myApply(zoeInfo,["前端菜🐔","努力学习中"])
5.效果
apply的实现
- 根据mdn 对call的描述我们确定需求
- 参数:第一参数得是一个函数,第二参数是数组
- 返回值是一个新函数
- 不会自动执行,需要手动调用
- 这里先偷个懒,没有考虑绑定函数也可以使用 new 运算符构造(回头有时间 再来填坑)
2.代码实现
- 借助已经实现的apply方法
Function.prototype.myBind=function(contex,arr=[]){
if(typeof(this)!=='function'){
throw new Error('first param not a function')
}
var self=this
return function(){
self.apply(contex,arr);
};
}
3.调用
const bindFunc=targetFunc.myBind(zoeInfo,["前端菜🐔","努力学习中","bind的代码实现"])
bindFunc()
4.效果
小结
没有最好的实现,只有更好的实现,欢迎评论区给出更好的实践和评论,请多指教 编辑器:jsbin
最后如果觉得本文有帮助 记得点赞三连哦 十分感谢