1.由一道面试题引发我对于call方法原理的思考
看了这道题如果对于call方法原理不懂的小伙伴肯定要懵逼了,我们都知道call用来改变函数执行时候,方法中的THIS指向。但是自己手写一个到底是怎么实现的呢??在百度搜索相关的内容一般都是介绍call方法的用法而没有涉及原理,在自己解决这个问题之后,决定记录一下分享给大家
- 下面看题吧
~function(){
function myCall(){
//=>实现你的代码
};
Function.prototype.myCall=myCall;
}();
let obj = {name:'Alibaba'};
function func(x,y){
this.total=x+y;
return this;
}
let res = func.myCall(obj,100,200);
//res => {name:'Alibaba',total:300}
2.我们代码加注释的详细讲解看一下这道题的深度
注意:细节点还是慢慢的,一不小心就懵逼了。笔者对每一步都进行了详细的阐述,掘金上Markdown我不会改变背景色,注释字体看着比较浅,读者可以粘贴到自己的编辑器里查看
/*
* 以这道题展开思考,我们想改变func函数中的THIS指向obj
* func:当前要执行的方法
* @params
* context:要改变的THIS指向(需要是一个对象,如果不是对象,可以把它变为对象)
* arg: 用剩余运算符接受的的参数都是未来执行func函数的时候,传递给函数的参数
* @return
* --
* 实现原理:让func和context之间建立关联(func是context的一个属性的属性值)
*/
function myCall(context, ...arg) {
//=>我的实现代码
//首先对于context为空的情况进行处理
context == null ? context = window : null;
//保证context传入的是对像,如果不是将其转化为对象
if (typeof context !== 'object' || typeof context !== 'function'){
//详细说说这一步的操作,第一次看到可能不太好理解,
//以一个数字为例加入形参context = 1,其实这一句代码等同于
//context = new Number(context);,也就是context会根据constructor去找到自己类型所属的包装类
context = new context.constructor(context);
}
//创建一个唯一值,避免与context本身的属性产生冲突
let uniqueKey = `?${new Date().getTime()}`;
//将原本要执行的函数以我们创建的为一致为属性赋给context对象,这一带你比较难理解的事this
//this既是我们的调用者func函数,看我们的调用func.myCall(obj,100,200);
context[uniqueKey] = this;
//函数执行结果,我们执行func方法,但调用这改为了我们的context,也就是obj
let result = context[uniqueKey](...arg);
//删除掉我们新增的属性,保证使用前后对象的准确性
delete context[uniqueKey];
return result;
};
//将我们自己封装的方法添加到函数的原型上,方便每一个方法调用
Function.prototype.myCall = myCall;
持续更新手写原生js内置方法系列,帮助大家更加的了解js原生一些方法的原理。如果对你有所帮助,别忘点个赞支持一下哦