大家好,我是前端西瓜哥。之前写过一篇手写的bind文章,直接使用native的调用方式。有读者表示,他在采访中也要求自己实现这个调用。那我们今天打个手写电话吧。apply的实现是一样的,只是调用形式有点不同。call的用法我们先来看一下Function.prototype.call()的用法。call()可以在调用函数的时候修改this的指向,剩下的参数会作为原函数的参数。调用接收的参数:第一个参数thisArg。表示this将指向的值。如果不是对象,也会通过Object()方法将其转换为对象。如果为null或undefined,this将指向全局对象(即window或global),或者在严格模式下(“usestrict;”),保持undefined或null;其余的参数。第二个和后面的参数将传递给原始函数。示例:functionsum(num1,num2){returnthis.val+num1+num2;}constobj={val:1};sum.call(obj,2,3);//6在上面的代码中,this指向obj。Function.prototype.apply也类似,只不过它的参数是以数组的形式存在的。上面写的调用相当于:sum.call(obj,[2,3]);call的实现JS函数中的this点是在运行时确定的,里面有很多规则,但是其中一条是:如果通过obj.fn()执行的时候,this会指向之前的obj对象.那么我们只需要将传入的对象和原来的方法拼接成上面的对象和方法的形式即可。执行的时候this可以乖乖的指向我们传入的thisArg。实现如下:Function.prototype.myCall=function(thisArg,...args){constcontext=Object(thisArg)||窗户;//构造一个唯一键constfn=Symbol();//组装成“object.method”形式并调用改变thiscontext[fn]=this;constret=context[fn](...args);//删除临时添加的key并恢复thisArgdeletecontext[fn];returnret;}这里我们使用Symbol()来创建一个唯一键,以防止用相同的名称覆盖thisArg的原始属性。执行完记得把这个key去掉,防止污染thisArg对象。如果面试官让你用ES5来实现,会复杂很多,所以我这里也给出实现。在此之前,我们先来学习一些前置知识。判断是否为严格模式varstrict=(function(){return!this})();在严格模式下,如果不指定this(通过bind、call、前面有一个对象等),就会得到undefinedmechanism。如果是非严格模式,这会获取到全局变量。ES5的fn(...args)实现了ES6...的展开运算符,可以拆分数组args并按顺序放入函数中。常量参数=[4,5,6];fn(...args);//等同于fn(4,5,6);那我们可以用ES5把数组拆分成一个参数,塞进函数里吗?好的,但我们要使用一个小技巧:函数方法。函数方法较少使用。它可以在运行时创建一个函数,最后一个参数是函数体的内容,前面的参数是函数的参数。constsum=newFunction('a','b','returna+b');sum(2,6)//8fn(...args)的ES5实现是:functionconstruct(fn,args){varlist=[];for(vari=0;i
