题目
实现一个 call / apply 方法。
解析
call 和 apply 方法一个重要的特征就是第一个参数可以绑定 this 指向。如下案例:
var a = 100;
var obj = {
a:1000;
}
function fun(){
console.log(this.a);//1000
}
fun.call(obj);
如上所示,如果没有使用 call 方法显式地将 obj 对象绑定到 this。fun 函数中 this 指向的就是 window。而 apply 与 call 的区别就是 apply 方法从第二参数开始是以数组的形式传参。
实现 call/apply 方法有两个关键点:
-
绑定 this。this 指向问题可以用一句话概括,“谁调用,this 就指向谁”。所以绑定 this 就需要将调用的方法添加到传过来的对象上去。再通过对象去调用。这样就可以实现将 this 指向这个对象。
即结合以上案例可以简单地理解为是将 fun 方法添加到 obj 对象的属性上。然后通过 obj 对象的属性去调用 fun 方法,就可以实现 fun 中的 this 指向 obj。 -
传递参数。除了将方法添加到对象上,还需要将参数进行传递。传递参数可以有三种方式, apply,eval(循坏数组,拼接字符串),ES6 的数组解构。以下案例中使用的是 ES6 的数组解构。
代码
实现一个 call 方法
Function.prototype._call = function(){
//1.将第一个参数(绑定this的对象)和剩余参数解构出来
let [thisObj,...arg] = [...arguments];
//2.如果第一个参数为空,则this为全局对象
if(!thisObj){
thisObj = typeof window === 'undefined'? global:window;
}
//3.把this(调用_call的方法) 赋值到该对象的一个属性上
thisObj._this = this;
//4.调用对象绑定的方法。
var result = thisObj._this(...arg);
//5.删除绑定的属性
delete thisObj._this;
//6.返回调用结果
return result;
}
//测试
var num = 18;
function Person(a,b) {
console.log(this.num + a + b);//60
}
var obj = {
num:20
}
Person._call(obj,20,20);
实现一个 apply 方法。
Function.prototype._apply = function(){
//1.将第一个参数(绑定this的对象)和数组参数(这里是apply与call的区别)解构出来
let [thisObj,arg] = [...arguments];
//2.如果第一个参数为空,则this为全局对象
if(!thisObj){
thisObj = typeof window === 'undefined'? global:window;
}
//3.把this(调用_apply的方法) 赋值到该对象的一个属性上
thisObj._this = this;
//4.调用对象绑定的方法。
var result;
if(arg){
if(!Array.isArray(arg)){
throw new Error("参数为数组")
}else{
result = thisObj._this(...arg);
}
}else {
result = thisObj._this();
}
//5.删除绑定的属性
delete thisObj._this;
//6.返回调用结果
return result;
}
//测试
var num = 18;
function Person(a,b) {
console.log(this.num + a + b);//60
}
var obj = {
num:20
}
Person._apply(obj,[20,20]);