TypeScript类箭头函数经扩展语法浅克隆后读取旧值问题求助
问题根本原因
- 你在类中使用箭头函数定义类属性方法的写法,会让该方法的
this在类实例化时就固定绑定到当前创建的实例,不会随调用对象变化而改变。 {...bob}扩展运算符和Object.assign都是浅拷贝逻辑,只会复制源对象自身的可枚举属性,包括已经绑定了旧实例this的bark方法,拷贝得到的新对象上的bark方法仍然绑定旧实例bob的上下文,因此读取的还是旧实例的name属性。- 额外补充:如果你用普通原型方法定义类函数,扩展运算符也不会拷贝原型链上的方法,新对象调用该方法会直接报错。react-data-grid做数据更新时默认采用immutable方式生成新普通对象,不会保留原类实例的原型链和方法绑定关系,这是问题的核心诱因。
可行解决方案
你可以根据自己的业务场景选择以下任意一种方案:
方案1:改用普通原型方法,手动维护实例原型
把类中的箭头函数方法改成普通原型方法,生成新对象时用Object.create绑定原类原型,再赋值属性:class Dog { name: string; // 改为普通原型方法,this随调用对象动态绑定 bark():string { return "hi, I am " + this.name; } constructor(name: string) { this.name = name; } } let bob = new Dog('bob'); // 创建新对象时先绑定原型,再合并属性 const jill = Object.assign(Object.create(Dog.prototype), bob, {name: 'jill'}); console.log(jill.bark()); // 输出 hi, I am jill该方案适合类构造函数无额外初始化逻辑的场景,改动量小。
方案2:每次数据更新时重新实例化类
不管是你自己更新数据,还是从react-data-grid拿到变更后的行数据,都重新用new关键字创建类实例,确保方法和上下文绑定正确:const jill = new Dog('jill'); console.log(jill.bark()); // 输出 hi, I am jill如果是配合react-data-grid使用,可以在给组件传
rows参数前,先把所有行数据遍历一遍重新实例化你的Row类,也可以用库提供的行数据转换钩子处理。方案3:改为接收实例作为参数的独立函数
放弃把方法挂载到类上,直接定义独立的工具函数,接收类实例作为入参,完全规避this绑定问题,该方案最适配React生态的immutable数据流设计:function bark(dog: Dog) { return "hi, I am " + dog.name; } const jill = {...bob, name: 'jill'}; console.log(bark(jill)); // 输出 hi, I am jill该方案无需处理类实例和原型逻辑,稳定性最高,推荐优先选用。
内容的提问来源于stack exchange,提问作者David Peters
相关产品推荐
相关产品推荐

