2

I have an object:

function Shape(color, position, coordinates){
    this.color = color;
    this.position = position;
    this.coordinates = coordinates;
    this.shrink = function(){
        reduce(coordinates);
    };
};

And one of many objects with a 'is a' relationship to the previous object.

function Sphere(color, position, coordinates, radius){
    this.radius = radius;
    this.role = function(){
        move(coordinates);
    };
};

And a separate Draw function which draws the shapes

function draw(shape){
    moveTo(shape.position);
    setColor(shape.color);
    sketch(shape.coordinates);
}; 

I know I should try use composition where possible but in some cases such as the one above, inheritance is a much more fitting model.

Without frameworks and as simply as possible how could I use prototypal inheritance or any other form to inherit the functionality and attributes of shape so I don't have to redefine them for every shape type I create and be able to pass arguments into the constructor of the inheriters object so they are passed to the object being inherited from.

EDIT

I searched the posts with similar titles and non of them provided examples regarding my specific situation, passing arguments in constructor and inheriting variables and functions. Also I find answer regarding this subject tend to present multiple options and I was looking for a more definitive answer on the standard approach (by way of example)

With regard to the so called definitive answer Performing inheritance in JavaScript I find that if I was to define all my attributes as described in prototype functions my script would be a mess, also it doesn't present what to do with arguments passed to the constructor.

Community
  • 1
  • 1
rogermushroom
  • 5,486
  • 4
  • 42
  • 68
  • 1
    possible duplicate of [Performing Inheritance in Javascript](http://stackoverflow.com/q/1586915/), [How to get a constructor function to inherit from a constructor function in Javascript?](http://stackoverflow.com/q/2263353/90527) – outis Mar 12 '12 at 21:42
  • @Ajai, "...you could definitely guess this out (prototyping)..." what do you mean exactly? Because the standard prototype property of a constructor only lets you define "class variables" (if I may use this term, by lack of a better one). – Roland Bouman Mar 12 '12 at 21:49
  • To be fair about the votes, the question is fairly useful and clear. On the other hand, it doesn't show any research effort. – outis Mar 12 '12 at 21:49
  • @whatsthebeef: note the syntax you have when setting methods within the constructor is wrong; you've reversed `function` and the method name. Since you're setting a property to an anonymous function, it should be `this.shrink = function() {...}`. Better still, set the methods on the prototype: `Shape.prototype.shrink = ...`. – outis Mar 12 '12 at 21:52
  • ... CMS' answer to "Performing Inheritance in Javascript" is the definitive one. Posting the same question, hoping for different answers isn't how SO works; it's supposed to be a sort of giant collection of FAQs. And be careful about your tone; Ajai may not have been kind, but that doesn't give you license to call him names. – outis Mar 12 '12 at 21:54
  • @RolandBouman: It is a known fact that JS does not support inheritance. I referred to Prototyping because that is when you can add function(or variables err..). Agreed that this is still a valid question. But my point is that you can google `https://www.google.com/search?aq=f&sourceid=chrome&ie=UTF-8&q=inheritance+javascript+stackoverflow` to easily find a solution. Probably could have remodified the question presenting with links that the OP has read from and if he still did not get it then it would definitely been a valid question. – Ajai Mar 12 '12 at 21:54
  • @outis good spot, thanks – rogermushroom Mar 12 '12 at 21:55
  • @whatsthebeef: I'm definitely not trying to demoralize or bitch with you in your "quest" to your solution. All I said was to try googling it out and if you still did not understand the solutions you could ask question related to what you actually didn't understand. Hhhhmm I think I am mistaken. Ps: I am not the one who downvoted the post. – Ajai Mar 12 '12 at 21:56
  • @Ajai I searched the posts with similar titles and non of them provided examples regarding my specific situation, passing arguments in constructor and inheriting variables and functions. Also I find answer regarding this subject tend to present multiple options and I was looking for a more definitive answer on the standard approach (by way of example) – rogermushroom Mar 12 '12 at 21:57
  • @outis, I just read CMS' answer here http://stackoverflow.com/questions/1586915/performing-inheritance-in-javascript but I don't see how this addresses the OP's key point, which is about inheriting instance variables. His code samples illustrate only methods, and for these the implementation is typically the same for all instances. The "Prototypal inheritance" as he describes it will infact cause non-function members (fields) to be inherited, but only at the "class level" - it does not give each instance its own set of fields, which is essential to the OPs problem. – Roland Bouman Mar 12 '12 at 22:12
  • @RolandBouman: whatsthebeef's original phrasing didn't specify exactly what he wanted to inherit; the sample code has both fields and methods. If whatsthebeef is only interested in inheritance of fields, the second question I linked in my first comment covers it. – outis Mar 12 '12 at 23:23
  • @outis Not sure about that, in the first revision I did state "inherit the functionality and attributes of shape" – rogermushroom Mar 13 '12 at 00:05
  • whatsthebeef what about my answer? I think this suits your use case, and it can be easily adapted to guarantee formal inheritence of instance variables even if they're not passed through the constructor argument. @outis: I guess there is no such thing as "the definitive answer" on matters of javascript inheritence schemes. The fact that you cite two earleir SO posts, and that one of them provides 2 different approaches, neither of which answers this question kind of proves that point. – Roland Bouman Mar 13 '12 at 06:52
  • whatsthebeef: that's what I though at first. Roland was the one who said the "key point" was inheriting fields. @Roland: the accepted answers for both the other questions do entirely answer this one. The first addresses inheriting methods, the second fields set by the constructor. You're right that there isn't a definitive approach, due to JS's simplicity (which can also cause issues to arise in the different approaches) and flexibility. – outis Mar 13 '12 at 10:16
  • ... Taking a closer look at the question about constructor arguments, your approach is given by both answers taken together: copy properties from an object and `apply` parent constructors. – outis Mar 13 '12 at 10:24
  • @outis you should have constructed a question with what you have said as it has turned out to be useful. – rogermushroom Mar 13 '12 at 14:40
  • @outis however neither explicitly address the problem of constructor arguments – rogermushroom Mar 13 '12 at 14:48
  • @whatsthebeef: that's exactly what the [second question](http://stackoverflow.com/q/2263353/90527) addresses. – outis Mar 13 '12 at 20:44

2 Answers2

1

Javascript does not have any native construct to achieve this. However, there are utility libraries that help you achieve this.

If you're interested in doing this, take a look at Dean Edward's Base library:

http://dean.edwards.name/weblog/2006/03/base/

You can probably use this as is to achieve what you want. At any rate, I can recommend every javascript prorammer to to read that code and try to understand how it works - it will make you a better programmer.

A very simple solution that does not rely on inheritance at all and also solves the problem of passing in the arguments would be to use object literals as arguments. To assign you simply copy all of the fields from the object literal like so:

//copy instance variables from source to target 
function copyInstanceVars(source, target){
    var p,v;
    for (p in source){
        if (source.hasOwnProperty(p)) {
            v = source[p];
            target[p] = v;
        }
    }
    return target;
}

//Shape, base class.
var Shape;
(Shape = function(config) {
    copyInstanceVars(config, this);  //copy instance variables from the config
}).prototype = {          //class members go in the prototype
    shrink: function(){
        reduce(coordinates);
    }
};

//Sphere, subclass of Shape
var Sphere;
(Sphere = function(config){
    Shape.apply(this, arguments);
}).prototype = copyInstanceVars(Shape.prototype, {  //inherit methods from Shape
    role: function(){
        move(coordinates);
    };
});

Then, when instantiating the objects, you'd do:

var shape = new Shape({
    color: "blue",
    ...,
    coordinates: {x:10, y:20}
});

var sphere = new Sphere({
    color: "blue",
    ...,
    ...,
    radius: 10
});

So, in this case, the instance variables are simply those fields present in whatever you pass into the constructor, and the copyInstanceVars function takes care of this copy process. (the hasOwnProperty check in there ensures we're only grabbing instance variables).

This example also illustrates how to inherit methods by using that same copyInstanceVars function. But this time we apply it to the prototype of the constructor (because we "declared" the methods as instance variables on the prototype)

Roland Bouman
  • 31,125
  • 6
  • 66
  • 67
  • Thanks, I find the code example makes what is a standard and simple operation in other languages look a little hacky. However I suspect this is the way it is with javascript inheritance (which was the reason behind writing what seemed like a duplicate question). The link you sent is very interesting, it specifies my problem clearer than I could and provides confirmation that my problem isn't completely down to a lack of understanding. I am still working through what's there and perhaps I will try out this base library or alternatively push all the variables into the prototype chain – rogermushroom Mar 13 '12 at 14:32
1

I generally find that parasitic inheritance is the easiest option in JavaScript:

function Sphere(color, position, coordinates, radius){
    var shape = new Shape(color, position, coordinates);
    shape.radius = radius;
    shape.role = function(){
        move(coordinates);
    };
    return shape;
};

The big downside is that you don't get to use the prototype chain - attaching methods to Sphere.prototype won't make them available on new Sphere instances.

nrabinowitz
  • 55,314
  • 10
  • 149
  • 165
  • This is what I began with but besides the lake of availability through prototyping the other problem was; code quickly became quite verbose when there were a lot of attributes. – rogermushroom Mar 13 '12 at 14:19
  • In that case, it's often a good idea to move to an `options` object instead of individual arguments: `new Shape(options)`, `new Sphere(options)`, etc. Then you just call the super constructor with the options object, and you don't have to keep track of constructor signatures. – nrabinowitz Mar 13 '12 at 16:58
  • I like the simplicity, obviously ignoring the security implications and assuming there won't be a deep inheritance tree I could just make `this.shape` and expose the prototype functions this way. – rogermushroom Mar 13 '12 at 17:15