JS 手写call和apply
call和apply都是改变this指向的方法,但是call和apply又有所不同
不同之处是:
call() 方法分别接受参数。
apply() 方法接受数组形式的参数。
以Math.max为例,Math.max是分别接受参数,返回最大值,我们分别手写call和apply方法,实现原生Math.max方法和接受数组形式参数的Math.max方法
注意
首先明确apply函数是定义在Function.prototype上的,为所有Function类型的对象所共享。
思路解析
手写call
- 明确this,this就是调用call/apply的原函数
- 判断this是否是函数类型,如果不是则抛出错误
- 确定执行上下文context,也就是调用call/apply传入的第一个参数,如果没有则指向window
- 获取剩余参数,[...argument]把伪数组转成数组,删除第一个参数
- 给context添加一个方法fn,赋值为this,这样调用context.fn时,this这个函数里面的this就会指向context,调用context.fn时把args解构出来作为参数传进去。
- 然后删除context的fn方法,以免污染context的属性
- 返回调用context.fn得到的值
Function.prototype.MyCall = function(context){
if(typeof this !== "function"){
throw new TypeError("error")
}
context = context || window
context.fn = this
const args = [...arguments].slice(1)
const result = context.fn(...args)
delete context.fn
return result
}
console.log(Math.max.MyCall(null, 1,3,2))
手写apply
- 明确this,this就是调用call/apply的原函数
- 判断this是否是函数类型,如果不是则抛出错误
- 确定执行上下文context,也就是调用call/apply传入的第一个参数,如果没有则指向window
- 获取第二个参数args,也就是一个数组,如果没有传参,则为空数组
- 给context添加一个方法fn,赋值为this,这样调用context.fn时,this这个函数里面的this就会指向context,调用context.fn时把args解构出来作为参数传进去。
- 然后删除context的fn方法,以免污染context的属性
- 返回调用context.fn得到的值
Function.prototype.MyApply = function(context){
// this就是谁调用的MyApply,谁就是这里的this
// 要先判断this是不是function
if(typeof this !== 'function'){
throw new TypeError("error")
}
// 是否有上下文
// 如果没有上下文就是window
context = context || window
// apply的特性的参数是数组
const args = arguments[1] || []
context.fn = this
const result = context.fn(...args)
delete context.fn
return result
}
console.log(Math.max.MyApply(null, [1,3,2]))