概要
我们在开发中经常使用解构赋值,这样可以使我们的代码显得更加精简,清晰,但是它同样面临this指向出错的问题。
本文将具体指出问题所在和解决方法。
代码及实现
问题提出
class Person {
constructor(){
this.name = "Tom";
this.age = 12;
}
getPersonInfo(){
console.log(this.name + " # " + this.age);
}
}
const { getPersonInfo } = new Person();
getPersonInfo();
执行结果:
getPersonInfo 方法并没有成功执行,this是undefined。
问题原因
事实上,解构赋值和下面的基本赋值方式是没有本质区别的,只是显得代码更加精简。
const person = new Person();
const getPersonInfo = person.getPersonInfo;
所以,基本赋值方式所面临的问题,解构赋值也同样会遇到。getPersonInfo 是类内方法,如果将其脱离对象的上下文使用,则方法中的this肯定变为undefined。
问题解决
类中方法需要支持解构赋值,就将其定义成箭头函数。
class Person {
constructor(){
this.name = "Tom";
this.age = 12;
}
getPersonInfo = ()=>{
console.log(this.name + " # " + this.age);
}
}
const { getPersonInfo } = new Person();
getPersonInfo();
此方法虽然比较简便,但是可能存在兼容性的问题,毕竟箭头函数是ES6的语法。
使用ES5的bind方法固定类内方法的this,无论是否需要解构赋值,都可以正常工作。
class Person {
constructor(){
this.name = "Tom";
this.age = 12;
this.getPersonInfo = this.getPersonInfo.bind(this);
}
getPersonInfo(){
console.log(this.name + " # " + this.age);
}
}
const { getPersonInfo } = new Person();
getPersonInfo();
用函数调用函数的方式解决上述问题
class Person {
constructor(){
this.name = "Tom";
this.age = 12;
const { getPersonInfo } = this;
const self = this;
this.getPersonInfo = function(){
getPersonInfo.call(self);
}
}
getPersonInfo(){
console.log(this.name + " # " + this.age);
}
}
const { getPersonInfo } = new Person();
getPersonInfo();
在this失效之前,将其赋值给self。后面getPersonInfo通过call方法被调用,内部的this也就被强制成当前Person类的实例。
使用函数调用函数的方式,除了可以解决this的问题,还可以让代码获得更高的灵活性。
function createUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
class Person {
constructor(idGenerator = createUUID){
const { setPersonInfo } = this;
const self = this;
this.setPersonInfo = function(name,age){
const id = idGenerator();
setPersonInfo.apply(self, [id, name, age]);
}
}
setPersonInfo(id, name, age){
this.name = name;
this.age = age;
this.id = id;
console.log(this.id + " # " + this.name + " # " + this.age);
}
}
const { setPersonInfo } = new Person();
setPersonInfo("Tom", 12);
上述代码在setPersonInfo方法中,需要三个参数id,name和age,其中name和age是需要通过但是传过来,但是id需要调用GUID生成器获取,理论上id的获取过程和用户的业务逻辑无关。
所以通过这种类似柯理化的方式,将参数切割,对外的接口中,只需要传递name和age,里面真正调用setPersonInfo方法的时候,再生成新的GUID。