在JavaScript/typescript中覆盖父构造函数中的默认值

n9vozmp4  于 5个月前  发布在  Java
关注(0)|答案(1)|浏览(65)

我有一个带构造函数的抽象Typescript类。这个构造函数接受一个对象,然后试图用对象中的数据设置类的属性。

export default class AbstractModel {
    constructor(properties: object) {
        Object.assign(this, properties);
    }
}

字符串
然后有几个类继承了这个AbstractModel类,例如:

import AbstractModel from "./abstract-model";

export default class Derived extends AbstractModel {
    firstname!: string;
    lastname!: string;
    age: number = 1;
}


我的假设是,当我创建一个新的Derived并在构造函数中传递{age: 10}时,新创建的Derived会将age设置为10。但是,age似乎总是1的初始值。其他没有初始值的属性也会按预期设置。

const derived = new Derived({firstname : "John", lastname: "Doe", age: 10});


输出量:

Derived {
  firstname: 'John',
  lastname: 'Doe',
  age: 1,
}


将其记录在AbstractModel的构造函数中,得到以下输出

export default class AbstractModel {
    constructor(properties: object) {
        Object.assign(this, properties);
        console.log(this);
    }
}


输出量:

Derived {
  firstname: 'John',
  lastname: 'Doe',
  age: 10,
}


将其记录在Derived的构造函数中,得到以下输出

export default class Derived extends AbstractModel {
    firstname!: string;
    lastname!: string;
    age: number = 1;

    constructor(properties: object) {
        super(properties);
        console.log(this);
    }
}


输出量:

Derived {
  firstname: 'John',
  lastname: 'Doe',
  age: 1,
}


有谁能告诉我为什么它会这样做?

2ledvvac

2ledvvac1#

您为age提供的初始值由您的子类构造函数赋值/定义<$。该赋值/定义在子类构造函数中调用super之后完成(如果你提供了显式的构造函数,或者如果你没有提供,那么就是默认生成的构造函数)。因此,age在你的子类中将是1,因为超类构造函数完成的赋值会被覆盖。这里有一个更简单的例子(只使用JavaScript,这样我们就可以在Stack Snippets中运行它):

class Base {
    constructor() {
        this.age = 42;
    }
}
class Derived extends Base {
    age = 1;
}

console.log(new Derived().age);

字符串
Derived的生成构造函数是:

constructor(...args) {
    super(...args);
}


..并且将age设置为1的定义/赋值<$发生在super(...args)部分之后。
我认为在您所展示的代码中修复它的最小更改方法是删除默认值并为Derived提供一个构造函数:

age: number;
constructor(obj: object) {
    super(obj);
    this.age = (obj as any).age ?? 1;
}


age!: number;
// ^−−− Note the "definitely assigned" assertion
constructor(obj: object) {
    super({age: 1, ...obj});
}


或类似的(Playground链接)。
也就是说,AbstractModel构造函数代码不是类型安全的,它会复制你提供给它的对象的所有属性,你可能需要重构它。
X1 m10n1x是否进行赋值(实际上,this.age = 1)或重新定义(Object.defineProperty(this, "age", {value: 1, /*...*/}))依赖于useDefineForClassFields配置选项。当该选项未启用时,它会进行赋值,当该选项启用时,它会进行重定义。重定义是JavaScript的类字段标准化的方式,因此,当类字段被引入JavaScript时,TypeScript中添加了配置选项来支持新的标准行为。

相关问题