【问题标题】:Access JavaScript class property in parent class访问父类中的 JavaScript 类属性
【发布时间】:2019-08-24 01:25:14
【问题描述】:

在 ES6 中是否有任何可能的方法——或者如果不是,是否有一个很好的解决方案(似乎很可能):

class Parent {
    constructor() {
        console.log(this.name);
    }
}

class Child extends Parent {
     name = "Child Name";
}

const c = new Child();
// Should console.log "Child Name";

(来自 Python,它完全可以工作!)

【问题讨论】:

标签: javascript es6-class


【解决方案1】:

要保留父类的name 属性的值,您只需将构造函数留在子类之外。或者,如果您想更新特定属性(在本例中为 name),则需要在构造函数 AFTER 中设置 this.name 调用 super() - 显式调用 @987654325 @ 是必须的,然后才能设置 this 属性,否则 JavaScript 会抛出错误。

这是我上面试图解释的一个例子:

class Parent {
  constructor() {
    this.name = "Parent Name";
  }
}

class ChildWithConstructor extends Parent {
  constructor() {
    super();
    this.name = "Child Name";
  }

  sayName() {
    console.log(`The constructor call updated the property value set in the parent contructor: ${this.name}`)
  }
}

class ChildWithoutConstructor extends Parent {
  sayName() {
    console.log(`No constructor call retains the property values set in the parent contructor: ${this.name}`)
  }
}

const c = new ChildWithConstructor();
const nc = new ChildWithoutConstructor();
c.sayName();
nc.sayName();

【讨论】:

  • 看来我想做的其实是不可能的。对于更多上下文,Parent 构造函数将开始构造某种数据对象,其中一个值是Child.name 变量(以便数据对象跟踪实际实例化了许多子类中的哪一个)。但是,正如 jfriend00 的回答所说,“在孩子可以初始化他们的实例数据之前调用父母的构造函数”(这表明我想要做的事情是不可能的)。
【解决方案2】:

在孩子初始化他们的实例数据之前调用父母的构造函数,因此您不能在父母的构造函数中引用孩子的实例。那是错误的 OOP 设计(至少在 Javascript 中)。如果父级想要访问构造函数中的某个属性,则在父级的构造函数中定义并初始化该属性(子级仍然可以使用它)。

父母不应该依赖孩子——孩子依赖父母。

所以,这是有缺陷的 OOP 设计。您没有展示您要解决的实际问题,因此我们无法真正建议针对实际问题的正确设计。


回顾一下,事情的顺序是:

  1. 调用子构造函数
  2. 子构造函数调用super(...)执行父构造函数
  3. 父构造函数初始化其实例数据
  4. 父构造函数返回后,子构造函数有机会初始化其实例数据

如果使用 ES6 类定义,您无法将这个顺序更改为不同的东西。


根据您对此答案的最新评论,我认为没有比只是为每个孩子添加额外的代码行更好的方法:

class Parent {
    constructor(name) {
        if (!name) {
            // could also throw an exception here if not
            // providing a name is a programming error and is not allowed
            this.name = "Default Name";
        } else {
            this.name = name;
        }
        console.log(this.name);
    }
}

class ChildA extends Parent {
     constructor() {
         super("ChildA Name");
     }
}

class ChildB extends Parent {
     constructor() {
         super("ChildB Name");
     }
}

const c = new ChildA();
// Should console.log "ChildA Name";

【讨论】:

  • 这里有一些误解。 1. “首先,name = "Child Name"; 不引用对象的属性。” OP 使用类字段语法,目前为stage 2 proposal。 2. “第二,你的孩子需要用super()调用父的构造函数。第三,你的孩子定义不正确的ES6语法。你需要定义一个子构造函数。”派生类不需要定义constructor。如果未定义,则隐式调用超类'constructor
  • “第四,在孩子初始化他们的实例数据之前调用了父母的构造函数,所以你不能在父母的构造函数中引用孩子的实例。”这部分是至少是正确的。
  • 这似乎是我想要的答案。简而言之,不,不可能。我试图在 Parent 中创建一个数据对象,该对象(除其他外)包含实例化它的孩子的 name 字段。我想知道是否有一种方法可以做到这一点,而不必在每个子类上定义一个构造函数(有很多),只需从子类中获取类属性。 (所以每个子类的变化只是一行,而不是我不需要的四行构造函数,除了定义一个变量。)但是,是的,因为首先初始化父级是不可能的。
  • @user2672537 - 我添加了一个代码示例。 IMO,使用 ES6 类实现这一点的最简洁的方法就是添加额外的代码行来定义子构造函数。
  • @JordanRunning - 仅供参考,我根据您的反馈清理了我的答案,并根据 OP 的 cmets 添加了一些附加信息。
【解决方案3】:

唯一的方法是在子构造函数上调用名为 init 的方法,并在父类上定义并使用 init 方法作为父构造函数。

这样,当子属性准备好时会调用 init

class Parent {
    constructor() {
      
    }
    
    init() {
      console.log(this.name);
    }
}

class Child extends Parent {
     name = "Child Name";
     
     constructor() {
      super();

      // call parent init
      this.init();
    }
}

const c = new Child();

【讨论】:

    【解决方案4】:

    parent 类中,无法访问child 类的字段。从孩子到父母 - 您可以使用 super

        class Parent {    
            constructor() {
              this.name="Parent Name";      
            };
        }
    
        class Child extends Parent {
          constructor(){
            super(name);
            console.log(this.name);
            this.name = "Child Name";
            console.log(this.name);    
          }
        }
    
        const c = new Child();
    

    【讨论】:

      【解决方案5】:

      据我所知,功能应该与属性相反。

      属性 - 第一个父级(至少在这个例子中)


      功能 - 先看看自己,没有就上来看看

      class Parent {
        constructor() {
          console.log(this.name());
        }
      }
      
      class Child extends Parent {
        name() {
          return "Child Name";
        }
      }
      
      const c = new Child();
      // Should console.log "Child Name";

      如果你想改变,而不是做this.name = 'something'
      你可以做一个函数

      setName(newName){
        this.name = function(){
          return newName
        }
      }
      

      是的,设置新值很难看,我什至不确定是否可行。

      【讨论】:

        【解决方案6】:

        有一个不错的方法
        请注意,this.constructor 是类,无论它在何处执行。
        所以我们可以用它来挂数据。

        class Parent{
          static prop = "default property"
          constructor(){
            console.log(this.constructor.name, this.constructor.prop)
          }
        }
        
        class Child extends Parent{
          static prop = "new property"
        }
        
        new Parent()
        new Child()

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-02-27
          • 1970-01-01
          • 1970-01-01
          • 2016-02-11
          • 1970-01-01
          • 2019-05-21
          • 2023-02-04
          相关资源
          最近更新 更多