1

I have a few problem with JavaScript inheritance and prototype. All the research I have made, in stackoverflow/google lead me to use the prototype of my class, but that's the point I want to avoid. I know JavaScript is not conceived that way but I'm sure it's possible, I'm just stuck.

I have two classes (or more maybe later). One is the base, that will be the mother of all, I want it to have all the basics attributes and method (like a basic OO). My objects are for geometry.


    function EnvObject(){
      this.position = {x: 0, y: 0};
      this.velocity = {x: 0, y: 0};
      this.mass = 0; // kg
      this.restitution = 0; // Restitution
      this.A = 0;
      this.Cd = 0; // Drag force
    
      function init(_x, _y, _mass, _restitution)
      {
        blabla
      };
    };
    
    function oCircle()
    {
     function foo(){}
     function bar(){}
    }
    function oSquare()
    {
     function foo(){}
     function bar(){}
    }

The main class provide all the information for my classes, like square or circle... Extend it with prototype will lead to big problem and a great thing, Methods are well shared (that's cool), but my attributes are also shared so when I change it in my Square class, the attributes will also change in Circle (which is a bad things)

I know the main solution is to not provides an interface for attributes, and place them only in the Square/Circle classes, but it's not very clean (I mean I write same attributes twice or more).

My main goal is to create a new class with 2 or more other class, without them sharing anything or maybe just few method? And eventually writing clean code? :)

So I've tried many scripts... All of them use that technique. Or maybe I'm just wrong which is probably true.

Also I know that class doesn't exist in JS, it's just a big function. Is it better to write object like this? I tend to like it much, because using function is a bit confusion in my opinion. Maybe inheritance is much easier in this way?

var envObject = {
    position: {x, y}
}
var oCircle = {
    foo: function(){}
}
Alen Siljak
  • 2,482
  • 2
  • 24
  • 29
h1fra
  • 324
  • 1
  • 3
  • 10

4 Answers4

1

Use a new Instance of the prototype object:

function oCircle() {
    function Circle() {
        this.foo = function(){};
    }
    Circle.prototype = new EnvObject();
    return new Circle();
};

Now, whenever you call new oCircle(), a new instance of EnvObject is used. This is what you expect of class-based inheritance.

Sebastian vom Meer
  • 5,005
  • 2
  • 28
  • 36
  • Why the downvote? This is an expert's Javascript pattern like taught by Stoyan Stefanov. What's the problem with my answer? – Sebastian vom Meer Jan 31 '13 at 16:39
  • Why does every returned object inherit from its own `EnvObject` instance? Don't understand what you mean with "expert". Maybe that pattern is useful in different situations, but not here. – Bergi Jan 31 '13 at 16:46
  • Because he doesn't want EnvObject properties to be shared when used as prototype. With expert I meant Stoyan Stefanov. – Sebastian vom Meer Jan 31 '13 at 16:49
  • But why are you then constructing two objects instead of only one that does not share the properties? This is not how prototypical inheritance should be used. – Bergi Jan 31 '13 at 17:19
  • I don't understand your question. I do this to have a unshared copy of these properties. – Sebastian vom Meer Jan 31 '13 at 17:26
  • No. You have one unshared copy, and an object that inherits from that copy. That's one too much. – Bergi Jan 31 '13 at 17:32
1

You've probably got issues with the nested objects (position, velocity). You will need to create the subobjects for each distinct instance separately.

Also I know that class doesn't exist in JS, it's just a big function. Is it better to write object like this?

No, not "better", it's just different. Instead of using constructor functions that are called with new and set properties on this, you can just use functions that return plain objects - less confusing.

Maybe inheritance is much easier in this way?

Not the prototypical inheritance that JavaScript uses. Also, you might want to have a look at this answer on how "classes" work in JavaScript.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Daaamn, you were right. I didn't know about that issue. I'v tested the all damn thing with this object, but it was working properly with simple attributes. Thank you a lot :)) – h1fra Jan 31 '13 at 19:57
0

Have you tried to apply the combination of prototype chaining and constructor stealing?

    function SuperType(){
        this.prop1 = // some value
        this.prop2 = // some other value
    }

    SuperType.prototype.function1 = function(){

    };

    function SubTypeA(){
        SuperType.call(this); // add inherited properties to this instance

        this.subTypeProperty1 = ...
    }

    SubTypeA.prototype = new SuperType();

    SubTypeA.prototype.subTypeFunction1 = function(){

    }

Each subtype will have its own inherited properties.

ppoliani
  • 4,792
  • 3
  • 34
  • 62
  • No, it won't. Each SubTypeA has the same prototype instance of SuperType. You want to have a new prototype instance for each instance of SubTypeA. Have a look at my answer. – Sebastian vom Meer Jan 31 '13 at 16:47
  • Well i think you're wrong @Sebastian. The SuperType.call(this); will add the prop1 and prop2 to the instances of the SubTypeA. You're right, the same instances will sit in the prototype, as well. But, the lookup order goes like that: instance members --> prototype members – ppoliani Jan 31 '13 at 16:50
  • Sorry, I haven't seen SuperType.call(this);. My bad ;) – Sebastian vom Meer Jan 31 '13 at 16:52
  • Yes, combining Constructor-Stealing with prototypical-inheritance IS the most fail-safe approach (that I've seen). I HAVE NO IDEA HOW IN THE WORLD THIS ANSWER HAS A "-1" DOWNVOTE! VOTING THIS UP NOW!!! – Cody Nov 07 '14 at 22:09
0

The Best Approach ... (I've seen)

This is a good starting point -- we use the combination of Constructor-Stealing & Prototypical-Inheritance (noted by #ppoliani above):

function SuperType() {
    this.super = 'type';
}
SuperType.prototype = { m: function () { } };

function C() {
    SuperType.call(this);
    this.key = 'value';
};
C.prototype = (new (function () {
    $.extend(this, new SuperType());
    this.some = 'thing';
})());

var c = new C();
console.log(c);

However, this could use some tuning up -- for instance, the C.prototype object (uses new so that we can use this -- which is good) extends this with new SuperType() and the method is added to this and not C.prototype -- not good. It also uses a non-native $.extend function -- not good.

Of course, the heavy use of inheritance can be a very undesirable methodology. Complex-Deep-Inheritance-Hierarchies often lead to extreme entropy in your Class Architecture. If your hierarchies are complex, deep architectures become maintenance, portability, and adaptivity nightmares. If this is the case, begin implementing The Decorator Pattern.

This is rather a demonstrative answer here to give readers better tools for manipulating the inheritance chain.

Hope this helps.

Community
  • 1
  • 1
Cody
  • 9,785
  • 4
  • 61
  • 46
  • Why not just use Object.create for the prototype part of inheritance? http://stackoverflow.com/questions/16063394/prototypical-inheritance-writing-up/16063711#16063711 – HMR Nov 08 '14 at 03:28
  • HMR, I looked into .create, tho I was at work and didn't have much time, it didn't seem that .create has 'mixin' ability. There's a necessity to keep the prototype properties at the same level as any additional prototype properties. We could assign the prototype as standard and use C.prototype.property = x, but I stay away from this approach as this syntax gets very chaotic for the reader quickly (if your me anyway). Can you give an example of what you mean to implement Object.create? – Cody Nov 08 '14 at 04:05
  • If its inheritance then Object.create is used to prevent having to create an instance of Parent and prevent Parent instance specific members on Child.prototype for mixins I iterate over prototype members and add a constructor to a mixin array to be called by Tue constructor. http://stackoverflow.com/questions/26784204/javascript-prototypal-inheritance-with-multiple-objects/26791771#26791771 – HMR Nov 08 '14 at 04:38
  • Thx HMR, I'll look into it deeper -- I like where your heads at :) – Cody Nov 08 '14 at 05:02