理解并手写 call() 函数
手写自己的call,我们要先通过call的使用,了解都需要完成些什么功能?
call()进行了调用,是个方法,已知是建立在原型上的,使用了多个参数(绑定的对象+传递的参数)。
我们把手写的函数起名为myCall,obj作为形参承载传过来的第一个参数(即绑定的对象)。
Function.prototype.myCall = function(obj){}
call的调用对this的指向进行了改变,而this是函数,这是前提(对this进行判断)。
Funtion.prototype.myCall = function(obj){
// 判断调用对象是否为函数
if(typeof this !== 'function'){
console.error('type error')
}
}
同理应当判断是否传入了参数,如果没有传入参数,则绑定的对象设置为window。
Funtion.prototype.myCall = function(obj){
if(typeof this !== 'function'){
console.error('type error')
}
// 判断绑定的对象
obj = obj || window;
}
要调用这个this方法,我们可以先将其作为对象的属性方法,然后调用。
Function.prototype.myCall = function(obj){
if(typeof this !== 'function'){
console.error('type error!');
}
obj = obj || window;
// 添加属性方法,并调用
obj.fn = this;
obj.fn();
}
call调用完后,拥有使用完方法后的返回值,所以肯定要将方法的执行结果保存并返回。
Function.prototype.mycall = function(obj){
if(typeof this !== 'function'){
console.error('type error!')
}
obj = obj || window;
obj.fn = this;
// 将执行结果保存,并返回
let result = obj.fn();
return result;
}
在原对象中,并没有obj.fn属性,所以我们要将其进行删除。
Function.prototype.mycall = function(obj){
if(typeof this !== 'function'){
console.error('type error!')
}
obj = obj || window;
obj.fn = this;
let result = obj.fn();
// 删除context.fn属性
delete obj.fn;
return result;
}
最后考虑下方法中使用的参数(从传递过来的第二个参数开始),通过slice()进行切割,并拼凑为数组。
Function.prototype.mycall = function(obj){
if(typeof this !== 'function'){
console.error('type error!')
}
// 获取正确参数
let args = [...arguments].slice(1)
obj = obj || window;
obj.fn = this;
let result = obj.fn(...args);
delete obj.fn;
return result;
}
最后通过一个例子,来验证是否达到call()的功能要求。
Function.prototype.myCall = function(obj) {
if (typeof this !== 'function') {
console.error('type error!');
}
obj = obj || window;
let args = [...arguments].slice(1);
obj.fn = this;
let result = obj.fn(...args)
delete obj.fn;
return result;
}
let dog = {
name: '狗',
eat(food1, food2) {
console.log(this.name + '爱吃' + food1 + food2);
}
}
let cat = {
name: '猫',
}
dog.eat.call(cat, '鱼', '肉'); // 猫爱吃鱼肉
dog.eat.myCall(cat, '鱼', '肉'); // 猫爱吃鱼肉
另外两篇:'对apply()函数的分析' 和 '对bind()函数的分析' 。
理解并手写 call() 函数的更多相关文章
- 理解并手写 bind() 函数
有了对call().apply()的前提分析,相信bind()我们也可以手到擒来. 参考前两篇:'对call()函数的分析' 和 '对apply()函数的分析',我们可以先得到以下代码: Functi ...
- 理解并手写 apply() 函数
apply()函数,在功能上类似于call(),只是传递参数的格式有所不同. dog.eat.call(cat, '鱼', '肉'); dog.eat.apply(cat, ['鱼', '肉']); ...
- WPF启动流程-自己手写Main函数
WPF一般默认提供一个MainWindow窗体,并在App.Xaml中使用StartupUri标记启动该窗体.以下通过手写实现WPF的启动. 首先先介绍一下VS默认提供的App.Xaml的结构,如下图 ...
- python 精华梳理(已理解并手写)--全是干货--已结
基础部分 map,reduce,filter,sort,推导式,匿名函数lambda , 协程,异步io,上下文管理 自定义字符串转数字方法一不使用reduce import re def str2i ...
- 前端面试题整理——手写bind函数
var arr = [1,2,3,4,5] console.log(arr.slice(1,4)) console.log(arr) Function.prototype.bind1 = functi ...
- 手写bind函数
实现bind函数 参考MDN提供的Polyfill方案 Function.prototype.myBind = function(context){ //这里对调用者做一个判断,如果不是函数类型,直接 ...
- C++之手写strlen函数
代码: int strlen(const char *str){ assert(str!=NULL); intlen=; while((*str++)!='\0') len++; return len ...
- js面试题之手写节流函数和防抖函数
函数节流:不断触发一个函数后,执行第一次,只有大于设定的执行周期后才会执行第二次 /* 节流函数:fn:要被节流的函数,delay:规定的时间 */ function throttle(fn,dela ...
- 【OpenCV学习笔记】之六 手写图像旋转函数---万丈高楼平地起
话说,平凡之处显真格,这一点也没错! 比如,对旋转图像进行双线性插值,很简单吧? 可,对我,折腾了大半天,也没有达到预期效果! 尤其是三个误区让我抓瞎好久: 1,坐标旋转公式. 这东西,要用 ...
随机推荐
- 为什么内部类调用的外部变量必须是final修饰的?
感谢原文:https://blog.csdn.net/u010393325/article/details/80643636 因为生命周期的原因.方法中的局部变量,方法结束后这个变量就要释放掉,fin ...
- curl: (6) Could not resolve host: mirrors.163.com; Unknown error 服务器上解析不了域名,换成ip可以
原因是DNS域名解析问题: 添加nameserver即可解决 echo nameserver 8.8.8.8 > /etc/resolv.conf 解释一下DNS服务 DNS(Domain Na ...
- StringUtils.isBlank(str)和StringUtils.isEmpty(str)的区别
1.StringUtils.isEmpty(CharSequence cs)实现源码 public static boolean isEmpty(CharSequence cs) { return c ...
- js判断当前浏览设备
前端开发经常遇到需要判断用户的浏览设备,是pc端还是移动端,移动端使用的是什么手机系统?android.ios.ipad.windows phone等等,有时候还需要知道用户浏览页面是在微信中打开还是 ...
- Java == 和 equals 的区别(面试描述)
== == 是一个比较运算符 既可以判断基本类型,又可以判断引用类型 如果判断基本数据类型,判断的是值是否相等 如果判断的是引用类型,判断的是地址是否相等,判断是不是同一个对象 equals equa ...
- Redis 竟然能用 List 实现消息队列
分布式系统中必备的一个中间件就是消息队列,通过消息队列我们能对服务间进行异步解耦.流量消峰.实现最终一致性. 目前市面上已经有 RabbitMQ.RochetMQ.ActiveMQ.Kafka等,有人 ...
- Solution -「洛谷 P4389」付公主的背包
\(\mathcal{Description}\) Link. 容量为 \(n\),\(m\) 种物品的无限背包,求凑出每种容量的方案数,对 \(998244353\) 取模. \(n,m ...
- 自学linux(安装系统,图形化界面,安装chrome)STEP1
1. 下载虚拟机VMware并安装 破解版: https://www.xitmi.com/2417.html 2. 下载centos7,6据说已经找不到了? 阿里云镜像: https://mirror ...
- Cobbler 批量安装操作系统
文章目录 环境准备 部署cobbler cobbler语法检查以及排错 问题1 问题2 问题3 问题4 问题5 问题6 问题7 问题8 修改dhcp模板 重启服务,再次检查 镜像配置 镜像导入 kic ...
- MyBatis功能点二:从责任链设计模式的角度理解插件实现技术
MyBatis允许对其四大组件(Executor,StatementHandler,ParameterHandler, ResultSetHandler)进行增强处理.在创建四大组件对象的时候 1.每 ...