什么是call,apply,bind
我们都知道,这三个方法都是和this指向有关的,那么具体是什么呢,简单来讲就是将某个函数放在指定的上下文变量中,在函数被调用的时候,this指向所绑定的对象。
语法
-
func.call(thisArg, param1, param2, ...)
将func
函数运行时的上下文绑定到thisArg
对象中,并给func
传入param1
,param2
参数 -
func.apply(thisArg, [param1,param2,...])
将func
函数运行时的上下文绑定到thisArg
对象中,并给func
传入[param1,param2]
类数组参数
- func.bind(thisArg, param1, param2, ...)
作用同1,但bind
返回的是func
函数的拷贝,而不是执行结果
什么是类数组
具有某些数组方法的对象变量,如:
let arrayLike = {
0: 1,
1: 2,
2: 3,
length: 3
};
类数组 arrayLike 可以通过下标进行调用,具有length属性,同时也可以通过 for 循环进行遍历。
但是需要注意的是:类数组无法使用 forEach、splice、push 等数组原型链上的方法,毕竟它不是真正的数组。那么类数组想使用数组原型链上的方法,该怎么办呢?请继续往下看。
call,apply,bind的作用
核心理念:借用方法
使用场景
- 方法借用(call,apply)
- 处理回调函数this丢失问题(bind)
class Page {
constructor(callBack) {
this.className = 'Page';
this.MessageCallBack = callBack; //回调函数
this.MessageCallBack('发给注册页面的信息'); // 执行PageA的回调函数
}
}
class PageA {
constructor() {
this.className = 'PageA';
//问题在下面这句
this.pageClass = new Page(this.handleMessage);//注册页面 传递回调函数
}
// 与页面通信回调
handleMessage(msg) {
console.log('处理通信', this.className, msg); // 'Page' this指向错误
}
}
let a = new PageA()
a.pageClass.MessageCallBack()//>>处理通信 Page apple
我们想要的结果是在调用a.pageClass.MessageCallBack
打印出的className
是A类的名称而不是Page
类的名称。
- 为什么会出现这个问题,就要考虑到执行
a.pageClass.MessageCallBack
发生了什么,我们知道,函数在哪里运行,this就会在哪里 - 由于是a的pageClass属性是Page类的一个实例,所以相当于把handleMessage方法,交给Page实例使用,所以在a.pageClass.MessageCallBack中的this是处在Page实例的环境中,所以就会打印出Page而不是PageA
- 修改方案
- 使用bind方法
this.pageClass = new Page(this.handleMessage.bind(this));
作用:实例Page的时候,告诉构造函数,在使用此参数(函数)的时候,是在PageA的实例下运行的
- 使用箭头函数
this.pageClass = new Page(() => this.handleMessage());
作用:因为箭头函数比较特殊,相当于告诉this.handleMessage()
方法,你在被调用的时候this就是pageA实例里,不会因传递而影响指向
手写call,apply,bind
未完待续
网友评论