【问题标题】:Class instance fields are undefined when assigned from parent class constructor从父类构造函数分配时,类实例字段未定义
【发布时间】:2020-10-26 13:48:50
【问题描述】:

在从父构造函数分配类字段的情况下,我试图了解为什么以下解决方案doesn't work 的动态:

class B{
  constructor(val){
        this.a = val;
    }
}

class A extends B{
  a;
  constructor(val){
    super(val);
  }
}

通过上述调用new A(1) 将返回一个实例,而A.aundefined

如果分配是通过命名function 而不是超级constructor 实现will work

class B{
  assignMe(val){
        this.a = val;
    }
}

class A extends B{
  a;
  constructor(val){
    super(null);
    super.assignMe(val);
  }
}

这会正确设置A.a = 1

这里有一个more complex implementation,它代表了我的真实使用场景。

为什么我不能使用constructor 来实现这一点?

【问题讨论】:

  • 您这样做是为了解决什么问题?从表面上看,让超类分配给子类声明的属性是一种反模式。
  • @T.J.Crowder 在我的真实场景中它不会分配给子类属性。即使class B 包含字段a,它仍然不起作用。
  • 如果Ba 并且A 没有,则它会这样做,如果B 负责初始化a,这就是您所期望的。
  • 如果您查看 Babel 对该代码的操作,super() 调用之后,属性“a”在 A 构造函数中被初始化为 undefined。这就是让 A 定义属性而不是 B 的语义。
  • playcode.io/697224 这是真实世界的场景

标签: javascript oop ecmascript-6


【解决方案1】:

发生这种情况的原因是,通过在 A 中声明 a 属性,当A 的构造函数到达指出它可以访问this(就在调用super()之后)。就好像您在构造函数中编写了这段代码(挥手一些细节):

class A extends B {
    constructor(val) {
        super(val);
        Object.defineProperty(this, "a", {
            value: undefined,
            writable: true,
            configurable: true,
            enumerable: true
        });
    }
}

您可以在 the public fields proposal 中找到有关此的详细信息([[Set]][[Define]] 设计点)。

您已经说过,在您的真实代码中,B 具有 a 属性以及就像 A 拥有它一样。解决方案是从A 中删除a 的声明,因此它使用B 在构造函数中初始化的声明:

class B {
    a;
    constructor(val) {
        this.a = val;
    }
}

class A extends B {
    constructor(val) {
      super(val);
    }
}

【讨论】:

  • @Constantin - 谢谢!我对链接代码的建议与上述相同:在BaseModel 中声明a 而不是在A 中。
猜你喜欢
  • 2017-11-12
  • 1970-01-01
  • 2016-01-26
  • 1970-01-01
  • 2022-11-04
  • 1970-01-01
  • 2021-04-28
  • 1970-01-01
  • 2012-10-18
相关资源
最近更新 更多