0

I've found many posts on class inheritance but not about this specific problem with changing properties on static classes.

Here is the problem: I'm trying to implement class inheritance on JavaScript on a static class that will have some general static methods and will be extended by child classes, static as well. Child classes may add more static methods and will change a configuration object. None of them will be instantiated so I assume that I can't create the body property on the constructor as it will not be called. I have the following code working but I think it might not be the right way to do this.

Could you suggest a better alternative?

class Animal{
    static get body(){
        return {
            legs: null,
            head: 1,
        }
    }
    static getLegs(){
        return this.body.legs;
    }
    static getHead(){
        return this.body.head;
    }
}
class Ant extends Animal{
    static get body(){
        return {
            legs: 6,
            head: 1,
        }
    }
}
class Monster extends Animal{
    static get body(){
        return {
            legs: 4,
            head: 2,
        }
    }
}
console.log(Animal.getLegs(), Animal.getHead());
console.log(Ant.getLegs(), Ant.getHead());
console.log(Monster.getLegs(), Monster.getHead());

2
  • The code is working, your child class functions are successfully shadowing the parent class functions. I'm not sure what you might be looking to improve here? Commented Jul 30, 2018 at 7:59
  • @CertainPerformance returning a new object every time I try to get the body doesn't look very performant. I wonder if there is a way of using variables or properties outside the construct. Commented Jul 30, 2018 at 8:01

3 Answers 3

2

classes are there for creating objects inheriting a prototype in a more convenient way. Actually JS has prototypal inheritance (objects got prototypes) so we could just use that:

 const animal = {
   body: { // you can fall back to a getter at any time
      legs: null,
      head: 1,
  },
  get legs(){
    return this.body.legs;
  },
  get head(){
    return this.body.head;
  }
};

const ant = Object.assign(Object.create(animal), {
  body: {
     legs: 6,
     head: 1,
  },
});

If you need the class for something else you can still set a property:

 class Animal{
    static get legs(){
       return this.body.legs;
    }
    static get head(){
        return this.body.head;
    }
 }

Animal.body = { legs: null, head: 1, };
Sign up to request clarification or add additional context in comments.

5 Comments

Is it possible to write that in class syntax?
@vandervals yes, it is
That is good, thanks! I couldn't figure out a way to put that body prop INSIDE the class declaration, hehe. This shall work of course.
@vandervals that will be possible in the future, static class properties are proposed already.
@JonasW. can you really set properties like that with Object.create()? I though you would need body: value:{legs:6, head:1} Similar to property descriptors
1

I am not sure about the problem, but you can write something like this if you are using Babel.

class Animal {
  static body = {
    legs: null,
    head: 1,
  };

  static getLegs() {
    return this.body.legs;
  }
  static getHead() {
    return this.body.head;
  }
}

class Ant extends Animal {
  static body = {
      legs: 6,
      head: 1
  };
}

class Monster extends Animal {
  static body = {
      legs: 4,
      head: 2,
  }
}
console.log(Animal.getLegs(), Animal.getHead());
console.log(Ant.getLegs(), Ant.getHead());
console.log(Monster.getLegs(), Monster.getHead());

Comments

0

If you don't want to create a new object each time body is getted, you might put each class's object into a variable and return that variable. Or, you might make the code cleaner with a Map that returns the object indexed at this, allowing for only one get body definition:

const { Animal, Ant, Monster } = (() => {
  class Animal {
    static get body() {
      return bodies.get(this)
    }
    static getLegs() {
      return this.body.legs;
    }
    static getHead() {
      return this.body.head;
    }
  }
  class Ant extends Animal {}
  class Monster extends Animal {}
  const bodies = new Map([
    [Animal, {
      legs: null,
      head: 1
    }],
    [Ant, {
      legs: 6,
      head: 1
    }],
    [Monster, {
      legs: 4,
      head: 2
    }]
  ]);
  return { Animal, Ant, Monster };
})();
console.log(Animal.getLegs(), Animal.getHead());
console.log(Ant.getLegs(), Ant.getHead());
console.log(Monster.getLegs(), Monster.getHead());

The IIFE ensures that the bodies are semi-private (though, they'll still be mutable if the object itself gets returned). If you want to additionally prevent the objects from being mutated when they're returned, you can use Object.freeze. (That doesn't guarantee that the objects won't be mutable - they can be unfrozen if done explicitly - but it'll make it a lot more difficult for accidental mutations to happen)

1 Comment

Well, compared to having get body for each class

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.