call 和 apply 的作用
他们都是改变this的指向,区别在于call可以传递多个参数,apply只能传递一个数组
语法
fn.call(context, param1, param2, ...)
fn.apply(context, [param1, param2, ...])
相关知识点
property原型连方法this的指向问题
函数都继承于 Function.prototype,(Function.prototype 中包含 call, apply, bind等方法),
原型链如下: f ---> Function.prototype ---> Object.prototype ---> null。property可以参考MDNthis可以参考MDN
疑问
- 为什么我们定义的函数可以使用
.(点)操作运算符来调用call或者apply方法 - 他们是如何实现改变
this的指向
实现call方法
// 给Function原型定义一个myCall方法
Function.prototype.myCall = function (context) {
var context = context || window
var args = [...arguments].slice(1)
// 此处的this 其实就是 调用myCall的那个函数(谁调用myCall,this就指向谁,这句话只适用与一般情况,这里这么说是为了便于理解this,还有其他特殊情况)
context.fn = this
var result = context.fn(...args)
delete context.fn
return result
}
以下是对上面代码的解释:
- 给
Function的原型连上定义一个myCall的方法,这样我们定义的函数就都能通过.(点)操作符来直接调用myCall这个方法 - 获取当前函数执行上下文
- 获取
myCall函数除过第一个参数的剩余参数 - 给当前上下文添加一个
fn临时属性,并将this赋值给fn,注意,context是当前执行函数的上下文,这一句的意思就是说,把要执行的函数赋值给当前执行上下文中的fn临时属性 - 将参数传入绑定到上下文的函数(即
context.fn(...args))并执行,将执行结果赋值给变量result - 因为当前上下文本身并不存在我们指定的fn,我们只是为了执行调
myCall的函数,所以,在前一步将其赋值给result变量后需要删除context的fn - 返回执行函数result
注意第4点中:
这里的this 指向的就是myCall的调用者,也就是fn.call(context, param1, param2)中的fn(一般情况下,谁调用了这个函数,那么这个函数的this就指向谁),了解更多关于this
实现apply方法
原理同上,只是获取参数时,获取的是myApply第二个参数
// 给Function原型定义一个myApply方法
Function.prototype.myApply = function (context) {
var context = context || window
// 此处的this 其实就是 调用myCall的那个函数(谁调用myCall,this就指向谁,这句话只适用与一般情况,这里这么说是为了便于理解this,还有其他特殊情况)
context.fn = this
var result = null
if (arguments[1]) {
result = context.fn(...args)
} else {
result = context.fn()
}
delete context.fn
return result
}
本文代码来源于前端进阶之道