了解call和apply
- 相同点:call和apply都是改变函数this指向并传入参数执行的一种方法。
- 不同点:call的传参方式为逐个传参,apply为数组传参。 举个栗子:
let obj = {
value: 1
}
function foo(name, age){
console.log(this.value)
console.log(name, age)
}
// 改变this指向为obj, 并传入参数
foo.call(obj, '谢大脚', 40) // 1 '谢大脚' 40
foo.apply(obj, ['永强', 28]) // 1 '永强' 28
call
分析:
试想一下,如果我们把foo函数变成obj的某一个属性,执行obj.foo
let obj = {
value: 1,
foo(){
console.log(this.value)
}
}
obj.foo()
不难看出,打印结果为1,根据这步操作可以知道,在call的时候,可以先把函数放到绑定的this的某一个属性上面,然后执行这个函数,最后删除这个属性。
第一版
根据call的使用方式可知call存在于Function.prototype中,所以我们开始写第一版,给它命名为call2。
Function.prototype.call2 = function(ctx) {
// function函数的this谁调用就指向谁,所以这里的this就是我们要执行的改变this指向的函数foo
// ctx为调用call2时传入的第一个参数(也就是新的this指向,就是obj)
ctx.fn = this
ctx.fn()
delete ctx.fn
}
// 测试一下
let obj = {
value: 1
}
function foo(){
console.log(this.value)
}
foo.call2(obj)
打印结果正常,开心的yia批(❁´◡`❁)
第二版
但是还没有实现参数的传递,如果需要传递参数,而且参数的数量也不是固定的,那该怎么办呢? 可以从Arguments对象中取值啊。
- 引用MDN的一句介绍:arguments对象是所有(非箭头)函数中都可用的局部变量。你可以使用arguments对象在函数中引用函数的参数。此对象包含传递给函数的每个参数。 因为arguments[0]为ctx,我们需要删除它,arguments为类数组,说到删除第一项,我瞬间想到了Array.prototype.shift.call(arguments),但是我们在手动实现call啊喂,肯定不能再调用call🤣。只能先用Array.from转换为数组。
Function.prototype.call2 = function(ctx) {
let args = Array.from(arguments)
args.shift()
ctx.fn = this
ctx.fn(...args)
delete ctx.fn
}
// 试一下
let obj = {
value: 1
}
function foo(name, age){
console.log(this.value)
console.log(name, age)
}
foo.call2(obj, '刘英', 27)
OK,一切正常
第三版
call还有另外一个属性就是当传入的被绑定的this为null的时候,默认绑定到全局this上面,函数体第一行增加代码
ctx = ctx || globalThis // 当ctx为null时,ctx指向globalThis
最终版
最后还有一点,假如函数有返回值,我们上面写的岂不是就有漏洞了,肯定是返回undefined的,所以修改代码为
Function.prototype.call2 = function(ctx) {
ctx = ctx || globalThis
let args = Array.from(arguments)
args.shift()
ctx.fn = this
let res = ctx.fn(...args)
delete ctx.fn
return res
}
手写call到这里就完成了,么么<( ̄ c ̄)y▂ξ
apply
apply其实就是参数传递方式和call不同而已,外卖要到了,就直接贴代码了😁。
最终版
Function.prototype.apply2 = function(ctx, arr = []) {
ctx = ctx || globalThis
ctx.fn = this
let res = ctx.fn(...arr)
delete ctx.fn
return res
}
// 试一下
let obj = {
value: 1
}
function foo(name, age){
console.log(this.value)
console.log(name, age)
return 'success'
}
console.log(foo.apply2(obj, ['刘英', 27]))
//打印结果为 1 '刘英' 27 'success'
好了,本篇内容就到这儿了,如果有错误或者不严谨的地方,请务必指正,万分感谢😛。