实现call、apply、bind
想要实现call、apply、bind,首先我们要知道这三个方法是用来干嘛的。
这三个方法是在函数实例原型上的方法,函数实例调用这三个方法可以改变函数内部的 this 指向,这就是这三个方法最重要的作用,具体这三个方法有什么使用区别就不详细阐述了,我们要来如何实现这三个方法?
首先我们要知道函数函数的 this 是在什么时候被绑定的,有哪些办法可以改变 this。
函数的 this 是在函数执行,创建函数执行上下文的时候被确定的,既然如此,我们也只能在这个时候改变函数的 this 指向。
那么函数的不同调用,会带来 this 的表现形式不一样,有如下四种调用:
- new 一个构造函数,
this指向new过程创建的对象 - 普通调用,一般指向
window - 通过对象调用,
this指向该对象 - 通过call、apply、bind的方式
想了解函数的调用带来的
this的不同表现形式,详细可以参考 # this的四种指向形式
显然这里我们可以巧妙的通过对象调用,隐式改变 this ,我们来实现一下。
myCall
Function.prototype.myCall = function(context, ...arguments) {
if(context === null || context === undefined){
context = window // 如果context不存在,则让context 指向 window
} else {
context = Object(context)
}
context.fn = this
// 这里的 this 指向调用 myCall 的函数,即我们要改变 this 的目标函数
// 通过将目标函数绑定到 context 上,再调用目标函数,此时目标函数的 this 将会指向 context
// 然后再执行目标函数
// 最后讲目标函数从 context 上移除
let result = context.fn(...arguments)
delete context.fn
return result
}
myApply
apply的实现和call类似
Function.prototype.myApply = function(context,arguments) {
if(context === null || context === undefined){
context = window // 如果context不存在,则让context 指向 window
} else {
context = Object(context)
}
context.fn = this
let result = arguments instanceof Array ? context.fn(...arguments) : context.fn()
delete context.fn
return result
}
myBind
bind方法同上面两种方法有点区别,它返回的是一个函数,这里简单实现一下,(因为我也没完全搞懂,等我完全搞懂再来更新)实际上的bind方法比较复杂。
Function.prototype.myBind = function(context, ...outArg) {
if(context === null || context === undefined){
context = window // 如果context不存在,则让context 指向 window
} else {
context = Object(context)
}
context.fn = this
return function(...innerArg) {
let result = context.fn(...outArg, ...innerArg)
delete context.fn
return result
}
}