当前位置: 首页 > news >正文

手写实现call,apply,和bind方法

手写实现call,apply和bind方法

call,apply和bind方法均是改变this指向的硬绑定方法,要想手写实现此三方法,都要用到一个知识点,即对象调用函数时,this会指向这个对象(谁调用this就指向谁)!

先设定一个测试函数及测试对象:

function func(num1, num2) {console.log("this:", this)return num1 + num2
}const testObj = {test: '测试用的对象'
}

手写实现call方法,

自己写的,所以把方法名定义为myCall。实现func的this指向testObj,输出num1 + num2的值。
测试用例:

const res = func.myCall(testObj, 1, 2);
console.log("res:", res);
// 输出this是{ test: '测试用的对象' },
//num1 + num2 计算结果 3

第一步:要实现任何函数都能使用这个myCall方法,则该方法需要定义在原型上面,因此:

Function.prototype.myCall = function(thisArg, ...args) {
}
// thisArg -- 待绑定this的参数对象。
// args -- 待传入的参数,
// 因为call传入参数是挨个传入,所以用rest参数方法,...args

第二步: 设置this,并调用原函数

Function.prototype.myCall = function (thisArg, ...args) {const key = Symbol('key');thisArg[key] = this;  // 步骤aconst res = thisArg[key](...args);  // 步骤bdelete thisArg[key]  // 步骤creturn res
}

步骤a解释:
给传入的thisArg对象添加一个过渡性的属性,此处用Symbol,因为Symbol具有唯一性,不会与thisArg里的属性发生重名覆写的情况。步骤a的this是原函数(本例中是func)。因为执行func.myCall()时,根据谁调用this就指向谁的原则,myCall()里的this即指向func。因此步骤a最终是往thisArg中添加了原函数func。

步骤b解释:
执行thisArg中刚刚添加的函数func。依旧是谁调用this指向谁的原则,func的this就指向的thisArg。

步骤c解释:删除掉无意义的过渡性属性。

所以上述测试用例中thisArg – testObj,num1 – 1, num2 – 2,结果打印如下:
在这里插入图片描述

手写实现apply方法

apply方法和call方法区别在于传入参数是个数组。其余实现原理相同。所以实现代码:

Function.prototype.myApply = function (thisArg, args) {const key = Symbol('key');thisArg[key] = this; const res = thisArg[key](...args); delete thisArg[key] return res
}const res = func.myApply(testObj, [1, 2]);
console.log("res:", res);
// 输出this是{ test: '测试用的对象' },
//num1 + num2 计算结果 3

手写实现bind方法

bind方法和call方法不同点在于bind返回的是个函数。所以实现代码如下

Function.prototype.myBind = function (thisArg, ...args) {return (...args2) => {  // 允许调用的时候继续传入参数const key = Symbol('key');thisArg[key] = this;  // 箭头函数中this是定义时的this,也就是myBind的thisconst res = thisArg[key](...args, ...args2)delete thisArg[key]return res}
}const res = func.myBind(testObj, 1);
console.log("res:", res(2));

结果:
在这里插入图片描述
简而言之,bind可以理解为返回一个函数,返回的函数中使用call改变了this指向。


http://www.mrgr.cn/news/64107.html

相关文章:

  • 【入门】买杯子
  • 【RabbitMQ的死信队列】
  • 上门回收小程序如何搭建?有个小程序收破烂也要高端?
  • K8s 不同层次的进程间通信实现
  • 【漫话机器学习系列】022.微积分中的链式求导法则(chain rule of Calculus)
  • odoo中@api.model, @api.depends和@api.onchange 装饰器的区别
  • 【MATLAB代码】三个CT模型的IMM例程,各CT旋转速率不同,适用于定位、导航、目标跟踪
  • 2024阿里云CTF Web writeup
  • 房贷利率定价调整机制变更的一点理解
  • Linux 进程终止 进程等待
  • 面试必会50题
  • MATLAB口罩检测
  • 大学城水电管理:Spring Boot应用案例
  • Ollama:本地部署与运行大型语言模型的高效工具
  • static全局/局部变量/函数和普通全局/局部变量/函数的区别
  • 赋值语句@赋值表达式@便于阅读和便于理解的比较
  • 【Linux中的第一个小程序】进度条及printf打印彩色字符
  • 《Python修炼秘籍》01踏上编程之旅
  • 满秩分解与奇异值分解
  • 机器人大模型GR2——在大规模视频数据集上预训练且机器人数据上微调,随后预测动作轨迹和视频(含GR1详解)
  • 树的遍历(先,中,后)
  • 【无人机设计与控制】改进无人机三维路径规划(蜣螂优化算法)Matlab程序
  • 除甲醛开窗通风的正确方法 消除甲醛的最好方法
  • 如何引用一个已经定义过的全局变量?
  • 【含文档】基于ssm+jsp的智慧篮球馆预约(含源码+数据库+lw)
  • 【含文档】基于Springboot+Vue的工商局商家管理系统 (含源码数据库+LW)