我已经使用Typescript playground构建了一个示例,但该行为与 typescript 无关。在代码中显示更容易一些(链接包括编译的 JS,对于那些希望忽略 TS 的人):
如果您扩展一个使用索引数组作为属性的类
class BaseClass {
_meta: {[key: string]: string};
constructor() {
this._meta = {};
}
}
class MyClass extends BaseClass {
prop1?: string;
constructor(init: Partial<MyClass>){
super()
Object.assign(this, init);
}
}
然后从基础模型使用反射 API 创建其他实例,您可以根据构建后续模型的方式获得不同的行为。
如果您创建一个新对象来分配给_meta
,它会按照您期望的方式工作:
const baseInstance = new MyClass({
prop1: 'base',
_meta: {
hello: 'world'
}
})
const reflectInstance = Reflect.construct(MyClass, [baseInstance]);
reflectInstance._meta = { hello: 'reflection' }
alert("1 " + JSON.stringify(baseInstance)) // as expected
alert("2 " + JSON.stringify(reflectInstance)) // as expected
但是如果您使用数组表示法分配给容器,则范围会受到污染,即它与源模型共享范围:
const contaminatedInstance = new MyClass({
prop1: 'contaminated',
_meta: {
goodbye: 'world'
}
})
const bogusInstance = Reflect.construct(MyClass, [contaminatedInstance]);
bogusInstance._meta['goodbye'] = 'contaminated';
alert("3 " + JSON.stringify(contaminatedInstance)) // _meta has unexpectedly changed
alert("4 " + JSON.stringify(bogusInstance)) // as a result of bogusInstance
有人知道为什么吗?我可以通过说 _meta 属性有一个公共地址来模糊地证明事情的合理性,并且因为它是扩展的,所以没有new
调用基本模型,因此使它变得通用;但是当它出现在单元测试之外时,这是一个很难记住的案例;尤其是在 PR 期间。
关于如何在仍然使用数组表示法的同时避免这种情况的任何建议都会很棒。
谢谢!