0%

用原生JS实现apply/call/bind

apply、call和bind的区别

1、相同点:

这三个的作用就是改变他们前面的函数执行时的上下文,即改变函数运行时的this指向,第一个参数都表示是this的指向,在this为null或者为undefined的时候,this默认指向window。

2、不同点:

apply的第二个参数是函数执行时传入的参数,apply时以数组的方式传入,一次传多个参数,只传一次,且函数是立即执行。

call 的第二个参数在函数执行的时候以参数列表的形式传入,一次传多个参数,只传一次,函数时立即执行的。

bind的第二个参数是动态传递参数,可以分多次传,但不会立即执行, 且会返回一个函数。

1
2
3
fn.bind(obj,1,2);
或者
fn.bind(obj,1)(2)

实现apply、call和bind

简单说一下他们的实现原理,fn.call(o) 它的实现原理就是o上定义一个新的属性m,m的值为要执行的这个函数fn,

即 :o.m=fn; 执行这个函数 fn(); 最后删除m这个属性。

那么这个函数是怎么获取呢,可以通过this来获取,this指向这个调用的函数fn

Function.prototype.apply()

1
2
3
4
5
6
7
8
9
10
Function.protoptype.apply=function(context=window, args){
if(typeof this!='function'){
throw new TypeError('type errror'); //因为this要指向apply前面要调用的函数,所以必须是一个函数
}
const fn = Symbol('fn');//保证fn作为属性时的唯一性
context[fn] =this;//this获取调用apply的函数(this会指向调用它的对象,所以会获取到到调用函数),fn是执行上下文的一个属性,这样能够保证fn的作用域是在context中的,从而实现传入context的绑定。
let result = contetx[fn](..args);//将参数传进去然后执行
delete contet[fn]; //删除新建的属性;
return result;//将调用的结果返回回去
}

Function.prototype.call()

1
2
3
4
5
6
7
8
9
10
11
12
//传入的参数是参数离列表
Function.prototype.call = function(context,=window, ...args){
if(typeof this !="function"){
throw TypeError('type error!');
}

const fn = Symbolp('fn');//此属性不可更改
context[fn]= this;
let result = context[fn](..args);
delete context[fn];
return result;
}

Function.prototype.bind()

1