要简单实现call、bind、apply首先要弄清楚这哥仨是啥,调用入参返回值都是什么,然后照葫芦画瓢,一点点填起来就好了;
能看思考咋实现的想必已经不需要在多赘言三个方法了,直接开始搞起;
首先这哥仨都是改变this指向,简化问题就是实现myX把fn.myX(arg)中的参数传递给fn,并把fn的this修改成arg;
var name = 'dahuang';
function a( ){
console.log(this.name);
}
obj = {name:'mimi'}
a();
a.call(obj)
a.apply(obj)
a.bind(obj)
/* log
dahuang
mimi
mimi
*/
call和apply在改变this的基础上,并且把调用的函数立即执行了;bind还需要另外调用一下,所以先处理call和apply
最简单的实现
Function.prototype.myX = function (arg){
arg.fn = this;
arg.fn();
}
a.myX(obj);
//等同于
let obj = {
name:'mimi',
fn:function(){console.log(this.name)}
}
obj.fn();
这里是通过给obj绑定方法fn,值为a,并且直接调用,进而改变了方法a的this;
众所周知,call和apply入参是有区别的,指着这一个最简单实现肯定不靠谱,所以接下来按照区别,分别实现myCall和myApply;
call
call接受若干个参数,返回调用函数的返回值,如果没有返回值就是undefined;
Function.prototype.myCall = function (arg){
arg.fn = this;
let rest = [...arguments].slice(1);//第一个是this把他删了剩下的就是参数
let result = arg.fn(...rest);//解构依次传入参数
delete arg.fn;//用完记得删掉,要不污染obj
return result;//有啥反回啥
}
apply
apply和call的区别就是接受参数是一个数组,其他度一样,直接吧mycall拿过来
Function.prototype.myCall = function (arg){
arg.fn = this;
let rest = arguments[1];//只需要第二个参数
let result = arg.fn(...rest);//解构依次传入参数
delete arg.fn;//用完记得删掉,要不污染obj
return result;//有啥反回啥
}
基本就完事了,但想起有可能不穿参数,这么写就会报error再加个兼容
Function.prototype.myApply = function (arg){
arg.fn = this;
let result;
if(arguments[1]){
result = arg.fn(...arguments[1]);
}else{
result = arg.fn();
}
delete arg.fn;//用完记得删掉,要不污染obj
return result;//有啥反回啥
}
bind
最后是bind,bind稍微麻烦一点点,首先bind返回的是一个新的函数,并且入参除了第一个是this,后边参数传啥都行;
Function.prototype.myBind = function (arg){
arg.fn = this;
console.log(arg)
let rest = [...arguments].slice(1);
let that = this;
return function(){
return arg.fn(...rest)
}
}
简单的几个实现可能不是很严谨,有些东西没有考虑到,但是基本满足了三兄dei的使用;写完之后发现并没有多难,静下心来慢慢屡就是了。