JavaScript模拟实现call、apply、bind
1、实现call()
js提供的call方法可以实现函数内this指向的改变,我们可以看下面这个例子
const obj={
a:'1'
}
function fn(){
console.log(this.a)
}
fn() //undefined
fn.call(obj) //1,指向obj
可以看到使用call我们可以将函数中的this强制指向obj对象。
下面我们来自己实现这个函数,我们都知道函数fn如果直接执行,则this是指向window的,而通过对象来调用一个函数,那么这个函数的this是指向这个对象的,那么我们就可以对上面的obj进行改造,将函数赋给obj,然后通过obj来调用这个函数即可
const obj={
a:'1',
fn:function(){
console.log(this.a)
}
}
obj.fn() //1
那么上面两个结合我们就可以写成下面这三部,先将函数给对象再通过对象调用,然后在删去这个函数即可
obj.fn=fn
obj.fn()
delete obj.fn
实现:
Function.prototype.mycall=function(context=window){
const obj=context||window //如果没有传参,默认指向window
obj.fn=this
const result=obj.fn()
delete obj.fn()
return result
}
当然我们的call还是可以给函数传参的,我们可以改写成下面这个样子
Function.prototype.mycall=function(context=window,...args){
const obj=context||window //如果没有传参,默认指向window
obj.fn=this
const result=obj.fn(...args)
delete obj.fn
return result
}
这样就大功完成啦下面就可以来测试啦
const obj={
a:'2'
}
function fn(name,age){
console.log(name)
console.log(age)
console.log(this.a)
}
fn.mycall(obj,'name',12) // 'name',12,2
2、实现apply()
apply的实现和call的实现类似,只不过一个传递的参数形式不同而已
Function.prototype.myapply=function(context=window,args){
let result;
const obj=context||window
obj.fn=this
if(Array.isArray(args)){
result=obj.fn(...args)
}else{
result=obj.fn()
}
delete obj.fn
return result
}
测试就跟上面的call一样的啦 这边就不贴了。
3、实现bind
bind的作用是返回一个新的函数,且这个函数的this指向已被改变,我们可以通过call或者是apply来完成,通过闭包返回一个函数来实现
Function.prototype.mybind=function(context=window,...args){
const that=this
return Function F(...args2){
return that.apply(context,args.concat(args2))
}
}
由于bind后产生的函数除了可以直接调用还会用作构造函数使用,所以我们在这里加个对他的判断,如果是构造函数,则直接返回实例对象。
Function.prototype.mybind=function(context=window,...args){
const that=this
const obj=context||window
return Function F(...args2){
if(this instanceof F){
return new that(...args,...args2)
}
return that.apply(obj,args.concat(args2))
}
}
我们加一层判断就可以啦,如果是构造函数则直接用原本的函数进行new就行啦