一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情。
前言
前端面试中,手撕call、apply、bind函数的实现是非常常见的,今天我们就来看下call和apply函数的自定义实现。
对自定义bind函数感兴趣的同学可以直接点击这里的传送门:经典面试题:手撕一个bind函数
call函数自定义实现
call函数定义:
call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。
举例:
// 声明Person类
class Person {
// 声明私有属性name、age
private name: string;
private age: number;
// 初始化时,传入name、age
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
/**
* @method printInfo
* @description 打印个人信息
* @param sex string 传入性别信息
*/
printInfo(sex: string) {
console.log({
name: this.name,
age: this.age,
sex: sex,
});
}
}
// 实例化类,创建对象
const p = new Person('Jhon', 20);
// 调用printInfo方法
p.printInfo('男'); // {name: 'Jhon', age: 20, sex: '男'}
// 调用系统方法call,改变this
p.printInfo.call({name: '韩梅梅', age: 10}, '女'); // {name: '韩梅梅', age: 10, sex: '女'}
自定义实现:
call方法需要注意的是this的指向、支持传入一个或多个参数,并且是立即返回函数执行结果。
因为JS中函数作用域是静态类型作用域,在函数声明的位置已经确定了~
function printThis () {
// 如果是在dom中指向window,如果是nodejs中指向global
console.log(this)
}
const man = {
name: '小名',
printThis () {
// 指向的是man本身
console.log(this)
}
}
那如何将原函数的this指向变为call方法中传入的this呢,我们可以借助对象调用自身方法的用法,更改原函数的this指向。
Up Code ~ 上码 ~
/**
* @method myCall
* @description 自定义call函数的实现
* @param context any 传入的this指向
* @param args any[] 传入的参数
*/
// @ts-ignore
Function.prototype.myCall = function (context: any, ...args: any[]) {
// 1. 处理context可能是null或者是undefined的情况
if (context === undefined || context === null) {
// 指向全局的this
context = globalThis;
}
// 2. 处理context类型不是对象的情况
if (typeof context !== 'object') {
context = new Object(context);
}
// 定义唯一key
const fnKey = Symbol();
// 将原函数的本身this,赋值给context的fnKey属性上,因为fnKey是唯一不重复的,所以也不会影响context本身的属性
context[fnKey] = this;
// 调用原函数 context[fnKey]这种形式,将this指向了context本身
// 传入传递的参数,接收结果
const res = context[fnKey](...args);
// 将在处理过程中新增加的fnKey属性再删除,不出现`脏代码`
delete context[fnKey];
// 返回最终的结果
return res;
};
功能测试:
// @ts-ignore
p.printInfo.myCall({ name: '韩梅梅', age: 10 }, '女'); // {name: '韩梅梅', age: 10, sex: '女'}
嘎嘎好使~
apply函数自定义实现
其实apply和call函数基本上就是一致的,唯一的区别是apply支持传递的参数是以数组形式传入的,简单调整下
// @ts-ignore
Function.prototype.myApply = function (context: any, args: any[]) {
// context的判断逻辑
if (context === undefined || context === null) {
// 指向全局的this
context = globalThis;
}
// 判断context不是对象
if (typeof context !== 'object') {
context = new Object(context);
}
// 定义唯一key
const fnKey = Symbol();
// 添加对象的方法
// 当前函数对象
context[fnKey] = this;
const res = context[fnKey](...args);
delete context[fnKey];
return res;
};
功能测试:
// @ts-ignore
p.printInfo.myApply({ name: '韩梅梅', age: 10 }, ['女']); // {name: '韩梅梅', age: 10, sex: '女'}
没有问题~~~
结语
以上就是胡哥今天给大家分享的内容,喜欢的小伙伴记得点赞、收藏呀,关注胡哥有话说,学习前端不迷路,欢迎多多留言交流...