javascript - ES6, access props set by the child from the parent's constructor - Stack Overflow

I am trying to set up a class hierarchy with ES6 classes.All entities will inherit from single Base cla

I am trying to set up a class hierarchy with ES6 classes.

All entities will inherit from single Base class. It will need to access properties exposed by the Child class in a generic manner. Like this:

class Base {
    constructor() {
        this.doSomethingWithProps();
    }

    doSomethingWithProps() {
        console.log(Object.keys(this));
    }
}

class Entity extends Base {
    constructor() {
        super();

        this.key = "value";
    }
}

Obviously, in the example above, Base class will not see the key prop set up by Entity. Ideally I would move the this assignment before super(), but that's not allowed. It would also be nice to be able to set properties before constructor, but AFAIK, that's not possible either.

The only solution I am left with is doing something like the following in each Entity:

class Base {
    doSomethingWithProps() {
        console.log(Object.keys(this));
    }
}

class Entity extends Base {
    constructor() {
        super();

        this.key = "value";

        this.doSomethingWithProps();
    }
}

However, besides being less than ideal, it will also create problems if I then want to inherit from Entity. doSomethingWithProps would then need to be able to detect if it's the "top-most" method in call hierarchy and only do its thing then. The only way to achieve that (that I can think of) would involve even more boilerplate.

Is there some solution I'm missing here? I'd be open to using a different OOP pattern if needed, although I'd like to stay as close as possible to native ES6 classes.

I am trying to set up a class hierarchy with ES6 classes.

All entities will inherit from single Base class. It will need to access properties exposed by the Child class in a generic manner. Like this:

class Base {
    constructor() {
        this.doSomethingWithProps();
    }

    doSomethingWithProps() {
        console.log(Object.keys(this));
    }
}

class Entity extends Base {
    constructor() {
        super();

        this.key = "value";
    }
}

Obviously, in the example above, Base class will not see the key prop set up by Entity. Ideally I would move the this assignment before super(), but that's not allowed. It would also be nice to be able to set properties before constructor, but AFAIK, that's not possible either.

The only solution I am left with is doing something like the following in each Entity:

class Base {
    doSomethingWithProps() {
        console.log(Object.keys(this));
    }
}

class Entity extends Base {
    constructor() {
        super();

        this.key = "value";

        this.doSomethingWithProps();
    }
}

However, besides being less than ideal, it will also create problems if I then want to inherit from Entity. doSomethingWithProps would then need to be able to detect if it's the "top-most" method in call hierarchy and only do its thing then. The only way to achieve that (that I can think of) would involve even more boilerplate.

Is there some solution I'm missing here? I'd be open to using a different OOP pattern if needed, although I'd like to stay as close as possible to native ES6 classes.

Share Improve this question asked Nov 18, 2016 at 12:11 panta82panta82 2,7213 gold badges21 silver badges38 bronze badges 3
  • Generally it is better to rely on position rather than inheritance as it could lead to a fragile base class. You can still use classes but inject another class in that contains the methods you need. This may also help if you do go down the class route: medium./@dan_abramov/… – mbx-mbx Commented Nov 18, 2016 at 12:21
  • If a base class has knowledge about derived classes, then something's utterly wrong. – a better oliver Commented Nov 18, 2016 at 13:23
  • @zeroflagL it doesn't exactly, just does generic initialize logic. Eg. coerce all properties, validate that nothing illegal is assigned etc. Sanity checks that are necessary due to dynamic nature of js. – panta82 Commented Nov 18, 2016 at 20:58
Add a ment  | 

4 Answers 4

Reset to default 5

What you are trying to do is quite impossible. The parent initialisation always runs before the child initialisation, so it is imperative that the parent constructor does not rely on properties that might be overwritten by the child. This is a language-agnostic problem, btw.

The solution is to use parameters for the constructor, which can be modified in the child before they reach the parent code:

class Base {
    constructor(key) {
        this.key = key;
        // do something with key
    }
}

class Entity extends Base {
    constructor() {
        super("value");
    }
}

console.log(new Entity);

or more generic

class Base {
    constructor(props) {
        this.doSomething(props);
        Object.assign(this, props);
    }

    doSomething(props) {
        return Object.keys(props);
    }
}

class Entity extends Base {
    constructor() {
        super({key: "value"});
    }
}

console.log(new Entity);

Also notice that constructors should always be pure. Their only purpose is to initialise the new instance from the arguments, and do nothing else like execute some side effects. A constructor should usually not need to call any (overwritable) instance methods (static methods are ok though).
So if you need to do something like that nonetheless when creating your instances, just don't do it in the constructor. Instead, call a method after using the constructor:

class Base {
    log() {
        console.log(Object.keys(this));
        return this;
    }
}

class Entity extends Base {
    constructor() {
        super();
        this.key = "value";
    }
}

var e = new Entity().log();

You can also abstract that out:

class Base {
    static createAndLog(...args) {
        var x = new this(...args);
        x.log();
        return x;
    }
    …
}
…

var e = Entity.createAndLog();

Depending on how plex you want to go, there's probably two routes you could go down.

1. Keep state in Base

If possible, pass the props you need from Entity into Base and maintain state there.

class Base {
    constructor(props) {
        for (var k in props) {
          this[k] = props[k]
        }
        this.doSomethingWithProps();
    }

    doSomethingWithProps() {
      console.log(Object.keys(this));
    }
}

class Entity extends Base {
    constructor(props) {
        super(props);
    }
}

let entity = new Entity({key: 'value'})
// ["key"]

2. Pass reference to Entity into Base

Note, I was incorrectly assuming separate instances of Entity.. this is overly redundant.

Not as simple, and will technically contain a self referencing key as Entity will inherit the child key from Base. This would definitely be considered a "wrong" approach, but I'm including it for the heck of it.

class Base {
    constructor() {
      this.child
    }
    
    registerChild(child) {
      this.child = child
      this.doSomethingWithProps()
    }
    
    doSomethingWithProps() {
      console.log(Object.keys(this.child));
    }
}

class Entity extends Base {
    constructor() {
        super();
        this.key = 'value'
        this.registerChild(this)
    }
}

let entity = new Entity()
// ["key", "child"]

I think the observation here should be: avoid calling a method that relies on the object's state in the constructor, since constructors are meant to build that state.

Actually, what you suppose to ask is about js syntax, however, the root of the issue is the idea of oop

Consider what extends mean when you write:

Entity extends Base

It means Entity make use of something from Base, the keyword is extends rather than something like municate, which means Base should NOT care about Entity at the first place. extends can also mean Entity has something which is not expected by Base, thus extends.

However, from my own point of view(correct me if I am wrong), there are some valid use cases in which parent class has some awareness of child class. For example: put some mon logic in Parent class to manipulate the property of Child, in such case, from the point of view of logic(not syntax), the child property should be static, i.e. belong to the whole class rather than a instance

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1742312655a4420205.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信