apply 和 call 其实都是通过this绑定中的隐式绑定, bind借作apply封装

apply和call是即时调用 bind不是

apply参数为数组,call参数为一个一个参数

apply

Function.prototype.MyApply=function(context,argsArr){
let handler=Symbol();//生成一个唯一的值,用来作为要context的属性key,储存当前调用call方法的函数,防止与context里面属性同名
if(typeof this !=='function'){
throw this+'is not a function,can\'t use Myapply'
}
let args=[]
// 如果传入的参数是不是数组,则无效
if(typeof argsArr==='object'||typeof context==='function'||typeof argsArr==='undefined') {
args=Array.isArray(argsArr)? argsArr:[];
} else {
// 如果为基本类型,如果是undefined,则无效,其它类型则抛出错误。
throw 'TypeError: CreateListFromArrayLike called on non-object'
}
//typeof判断context是否为object类型(typeof null ==='object')
if(typeof context ==='object') context=context??window;
else{
if(typeof context ==='undefine') context=window;
else{//其他类型全部用Object封装 1=>Number:1 fun=>Function:func
context=Object(context);
}
}

context[handler]=this;
let result=context[handler](...args)
delete context[handler];
return result;
}

call

和apply基本一样 只是参数类型不一样

Function.prototype.MyCall=function(context,...args){
let handler=Symbol();//生成一个唯一的值,用来作为要context的属性key,储存当前调用call方法的函数,防止与context里面属性同名
if(typeof this !=='function'){
throw this+'is not a function,can\'t use Mycall'
}
// 如果传入的参数是不是数组,则无效
if(typeof argsArr==='object'||typeof context==='function'||typeof argsArr==='undefined') {
args=Array.isArray(argsArr)? argsArr:[];
} else {
// 如果为基本类型,如果是undefined,则无效,其它类型则抛出错误。
throw 'TypeError: CreateListFromArrayLike called on non-object'
}
//typeof判断context是否为object类型(typeof null ==='object')
if(typeof context ==='object') context=context??window;
else{
if(typeof context ==='undefine') context=window;
else{//其他类型全部用Object封装 1=>Number:1 fun=>Function:func
context=Object(context);
}
}

context[handler]=this;
let result=context[handler](...args)
delete context[handler];
return result;
}

bind

Function.prototype.MyBind=function(context,...args){
let that=this;
if(typeof this !=='function'){
throw this+'is not a function,can\'t use Mybind'
}
let newF=function(){
//倘若是用new this会指向函数本身,但是函数本身调用的话this会丢失然后指向window
that.call(this&&this !==window?this:context,...[...args,...arguments]);
}
//通过原型链继承的方式让原函数的原型和新函数的原型,都在通过new关键词构造的新对象的原型链上
var f=function(){};
f.prototype=that.prototype;
newF.prototype=new f();
return newF;
}

new

function Mynew(constructor,...args){
//第一步,创建一个空对象
let obj=Object.create(null);
//第二步 该对象的__proto__指向构造函数的原型prototype,连接原型
obj.__proto__=constructor.prototype
//第三步 执行构造函数,this绑定为obj,对obj进行操作
var result=constructor.apply(obj,args);
//判断构造函数执行是否为对象,若为对象则返回对象,无则返回obj
return typeof result==='object'?result:obj;
}

func.call.call(func);

分析:

func.call其实是call函数的地址,也就是说上面的其实是,call.call(func)

此时,第二个call中this是第一个call,context=func,

然后再是,context[handler] = 第一个call,也就是,此时执行context[handler](…args),也就是说,第一个call里面的this是func,args为空,那么this自动为window,也就是说

就是在func中this为window执行