解决结构赋值中函数的this指向问题

发布于:2022-12-31 ⋅ 阅读:(359) ⋅ 点赞:(0)

概要

我们在开发中经常使用解构赋值,这样可以使我们的代码显得更加精简,清晰,但是它同样面临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。


网站公告

今日签到

点亮在社区的每一天
去签到