javascript 无法从父类的构造函数设置子类属性

oyjwcjzk  于 2023-02-07  发布在  Java
关注(0)|答案(3)|浏览(137)

我在nextjs中使用了这段代码,它总是记录

class A { // A: Model
    constructor(source){
        Object.keys(source)
        .forEach(key => {
            if(!this[key]){
                this[key] = source[key];
            }
        });
    }
}

class B extends A{ // B: User
    first_name: string;
}

let v = new B({first_name: "nof"});
console.log(v)
// B { first_name: undefined }

但是当在非nextjs项目中使用时,它只是工作并显示n1和m2,我相信这与nextjs上的一些配置有关;你知道如何不用在B类中声明构造函数就能实现吗?
这是最初的例子,保留在这里作为下面答案的参考:

class A {
    constructor(){
        this.init()
    }
    init(){
        this["n1"] = "nof";
        this["n2"] = "nof";
    }
}

class B extends A{
    n1: string;
}

let v = new B();
console.log(v)
// B { n1: undefined, n2: 'foo' }
pbossiut

pbossiut1#

结果与预期一致。当构造新对象B时,它首先构造A,然后n1和n2都设置为'nof'。然后构造B,并用未设置(总是未定义)的变量覆盖n1,因此n1 =未定义,n2仍应为' nof'。

lpwwtiir

lpwwtiir2#

您看到这种行为是因为您现在启用了useDefineForClassFields,而之前您没有启用它。
对类字段使用“定义”-useDefineForClassFields
此标志用于迁移到即将到来的类字段标准版本的过程中。TypeScript在TC 39中批准之前许多年就引入了类字段。即将到来的规范的最新版本与TypeScript的实现具有不同的运行时行为,但语法相同。
此标志切换到即将到来的ECMA运行时行为。
您可以在3.7发行说明中阅读更多有关转换的信息。
A的构造函数运行完之后,B的(隐式)构造函数 * 重新定义了 * 属性(替换了A定义的属性),丢失了在这个过程中创建的值A

class A { // A: Model
    constructor(source){
        Object.keys(source)
        .forEach(key => {
            if(!this[key]){
                this[key] = source[key];
            }
        });
    }
}

class B extends A{ // B: User
    first_name/*: string*/;
}

let v = new B({first_name: "nof"});
console.log(v)
// B { first_name: undefined }

您可以关闭该设置以从该代码中获得所需的输出;playground link*(我还没有尝试修复其中的其他类型错误)*.**但我强烈建议您更新代码。**仅从设计Angular 来看,A不应该初始化它没有定义的属性。此外,将接收到的对象的所有属性转储到正在初始化的示例中也不是类型安全的。
我建议简单地编写构造函数并让它们复制它们应该复制的数据,这样可以防止示例从source获取不存在的属性,如下面的JavaScript示例所示(此处为TypeScript版本 [再次声明,我没有尝试修复其他类型错误]):

class A { // A: Model
    constructor(source){
        Object.keys(source)
        .forEach(key => {
            if(!this[key]){
                this[key] = source[key];
            }
        });
    }
}

class B extends A{ // B: User
    first_name;
}

let v = new B({first_name: "nof", shouldNotBeHere: "Hi there!"});
console.log(v);
// B { first_name: "nof", shouldNotBeHere: "Hi there!" }
//                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

但是,如果您想让A执行盲拷贝,可以通过关闭该标志来消除编译器错误(但不是问题)。

toe95027

toe950273#

您是否可以尝试通过添加类型声明来显式声明类B中“n1”属性的类型:
n1!: string;
属性名称后面的“!”符号用于声明非空属性,以确保“n1”始终具有值。

相关问题