面试手写call、apply、bind

160 阅读3分钟

手写call

目的:fn执行,this指向传进来的第一个参数,本例中是context 剩余的参数用剩余运算符表示为...parmas 思路:首先给Function的原型添加一个属性newcall,然后将此属性封装成一个改变this指向的函数。第一步:函数中的this代表的是fn,因此给context(obj)添加一个属性,使其属性值为fn,但是此属性有可能与原有的属性相同,并将原属性的属性值覆盖,因此添加的属性应为唯一值,所以需要用Symbol定义一个变量,将其作为添加的属性;然后通过context执行这个函数,此时函数前面有点,并且点前面是context,所以执行的函数中的this为context,之后将函数执行执行结果返出去;但那是因为给context添加了一个属性,所以在将函数结果翻出去之前删掉这个属性。第二步:但是又因为context不确定是否为对象类型,所以应该在最开始用typeof判断其是否为对象类型,但是typeof null也为object,所以一开始应将其排除掉

Function.prototype.newcall=function newcall(context,...parmas){
if(context==null)context=window;
if(typeof context !=="object"&&typeof context !=="function") context=Object(context)
let key=Symbol('key'),result;
context[key]=this;
result=context[key](...parmas);
delete context[key];
return result;
};

let fn=function fn(x,y){
console.log(this);
return x+y;
};
let obj={
name:"haha"
};
let result=fn.newcall(obj,10,20)

手写apply

目的:fn执行,this指向传进来的第一个参数,本例中是context; 思路:首先给Function的原型添加一个属性newcall,然后将此属性封装成一个改变this指向的函数。第一步:函数中的this代表的是fn,因此给context(obj)添加一个属性,使其属性值为fn,但是此属性有可能与原有的属性相同,并将原属性的属性值覆盖,因此添加的属性应为唯一值,所以需要用Symbol定义一个变量,将其作为添加的属性;然后通过context执行这个函数,此时函数前面有点,并且点前面是context,所以执行的函数中的this为context,之后将函数执行执行结果返出去;但那是因为给context添加了一个属性,所以在将函数结果翻出去之前删掉这个属性。第二步:但是又因为context不确定是否为对象类型,所以应该在最开始用typeof判断其是否为对象类型,但是typeof null也为object,所以一开始应将其排除掉

Function.prototype.newapply=function newapply(context,parmas){
if(context==null)context=window;
if(typeof context !=="object"&&typeof context !=="function") context=Object(context)
let key=Symbol('key'),result;
context[key]=this;
result=context[key](...parmas);//因为传进来的是数组,所以此处用展开运算符
delete context[key];
return result;
};

let fn=function fn(x,y){
console.log(this);
return x+y;
};
let obj={
name:"haha"
};
let result=fn.newapply(obj,[10,20])

手写bind

BIND原理:执行bind方法。我们先把最后要执行的函数、要改变的this、要传的参数存储起来,返回一个匿名函数给绑定事件;当事件触发,我们先把绑定的匿名函数执行,在匿名函数中,再执行我们要执行的函数

/*
document.onclick=fn.bind(obj,10,20)等价于document.onclick=function(){fn.call(obj,10,20)
} 
*/
Function.prototype.newbind=function newbind(context,...parmas){
let self=this;
return function(){
self.call(context,...parmas)
}
}

let fn=function(x,y){
console.log(this);
console.log(x,y)
}
let obj={
name:"刘德华"
}
document.onclick=fn.newbind(obj,10,20)