www.webdeveloper.com
Results 1 to 7 of 7

Thread: Inheritance with customization

  1. #1
    Join Date
    Apr 2012
    Posts
    3

    Question Inheritance with customization

    Hi. I've got a simple problem I'm trying to solve, but I can't find a solution that works online. Here's what I'm trying to do, boiled down:

    1. Define a class of objects, called Mover, that would basically look like this:
    Mover
    - has x property
    - has y property
    - has move method
    - has Constructor that takes two arguments, x and y, and sets these to the x and y properties of the object.

    2. Define a second class of objects, let's say "Cat", that inherits from Mover, like this:
    Cat
    - Inherits x, y, and move from Mover.
    - has breed property.
    - has a Constructor that takes /three/ arguments {x, y, breed} that sets the breed property to the breed argument, and then passes the arguments to the Mover constructor.

    3. Call one function that returns a new Cat object.
    4. Be able to access Cat.move()

    Does that makes sense? I've seen all sorts of examples online, and thy get very complicated very quickly, and I haven't seen one that actually works! Here's what I've got so far:

    Code:
    function Mover(x, y){
    	this.x = x;
    	this.y = y;
    	// #note_1
    }
    Mover.prototype.move = function(delta_x, delta_y){
    	do_stuff();
    };
    function Cat(x, y, breed){
    	// #note_2
    	this.breed = breed;
    }
    // #note_3
    var my_cat = new Cat(1,2, "tabby");
    #note_1: There are several ways I could have given the Mover class a move function. I could have done "this.move = function", but that would create a new function for each object. I could have created a global function with a name like "mover_move" and then set "this.move = mover_move", but that would clutter the list of global functions. Setting a function on the prototype seems to be the way I should be doing this.
    #note_2: I could call Mover.apply(arguments) here, but that would only take care of the x and y variables. The my_cat variable would not have a move() method.
    #note_3: What am I supposed to be doing here? I feel like I should be doing some sort of complicated Cat.prototype = Mover.something.something.prototype.

    I'm also seeing a lot about Object.create(type, {many_braces: {value: magic_number}}), but 1) that is messy as all hell, 2) the value of many_braces cannot be changed from magic_number in the future, 3) this still doesn't solve the issue of having multiple constructors called. Alternately, I may just have no clue how to use this feature.

    So here's my question: what would you write in order to make a Cat object that inherits from Mover?

  2. #2
    Join Date
    Aug 2007
    Posts
    3,767
    Parasitic inheritance describes exactly how you could do what you want. Really, that's trying to force a pattern on JavaScript that it wasn't really designed for, so you might be better off rethinking how you're going to implement this, I'm not sure without knowing more details.

  3. #3
    Join Date
    Jul 2003
    Location
    The City of Roses
    Posts
    2,503
    #note_1: There are several ways I could have given the Mover class a move function. I could have done "this.move = function", but that would create a new function for each object. I could have created a global function with a name like "mover_move" and then set "this.move = mover_move", but that would clutter the list of global functions. Setting a function on the prototype seems to be the way I should be doing this.
    You did the right thing here. This is the standard practice.

    #note_2: I could call Mover.apply(arguments) here, but that would only take care of the x and y variables. The my_cat variable would not have a move() method.

    #note_3: What am I supposed to be doing here? I feel like I should be doing some sort of complicated Cat.prototype = Mover.something.something.prototype.
    The simplest way to make Cat inherit from Mover is to set Cat's prototype to a new instance of Mover.

    Cat.prototype = new Mover();

    You should still invoke Mover.apply(this, arguments) from the Cat constructor.

    I'm also seeing a lot about Object.create(type, {many_braces: {value: magic_number}}) ...
    Object.create is generally considered a cleaner way to set up inheritance than the example I showed above. The criticism of the above inheritance is that it unnecessarily invokes the Mover constructor. Object.create creates a new object that inherits from the passed object without invoking the constructor.

    Cat.prototype = Object.create(Mover.prototype);

    ... but 1) that is messy as all hell ...
    Regarding the second argument to Object.create, I don't think there's a consensus opinion among the JavaScript community, but I agree with you that the syntax seems unnecessarily verbose.

    ... 2) the value of many_braces cannot be changed from magic_number in the future ...
    That's the default behavior, yes, but that behavior can be changed.

    Code:
    Cat.prototype = Object.create(Mover.prototype, {
        many_braces: {
            value: 'magic_number',
            writable: true,
            enumerable: true,
            configurable: true
        }
    });
    ... 3) this still doesn't solve the issue of having multiple constructors called.
    Also true. You still have to do this manually with Mover.apply(this, arguments). There are several libraries that provide a custom mechanism for class definition and inheritance that fill missing features like this one, but if you're going to use just native JavaScript features, then this is what you're stuck with.
    Last edited by Jeff Mott; 04-14-2012 at 08:24 PM.
    for(split(//,'))*))91:+9.*4:1A1+9,1))2*:..)))2*:31.-1)4131)1))2*:3)"'))
    {for(ord){$i+=$_&7;grep(vec($s,$i++,1)=1,1..($_>>3)-4);}}print"$s\n";

  4. #4
    Join Date
    Jan 2007
    Location
    Wisconsin
    Posts
    2,120
    For what it's worth, you should bear in mind that this:

    PHP Code:
    var Class = function() {
      
    this.doSomething = function() {}

    .. is slower during object construction, but faster during method calls compared to this:

    PHP Code:
    var Class = function() {
    }

    Class.
    prototype.doSomething = function() {} 
    If my memory is correct, method calling decrease for each level of inheritance using the 2nd syntax.

    So, in general, if you're calling object methods more often than you're creating those objects, it's best to use the 1st syntax, attaching methods directly to the object in the constructor. This actually makes overriding and calling superclass methods fairly simple as well. And I actually prefer the syntax:

    PHP Code:
    var SubClass = function() {
      Class.
    call(this);

      
    this.anotherDoSomething = function() {}

      
    // override doSomething, but with some dependence on
      // the base doSomething method.
      
    this.baseDoSomething doSomething;
      
    this.doSomething = function() {
        
    this.baseDoSomething();

        
    // now do more stuff ...
      
    }


  5. #5
    Join Date
    Apr 2012
    Posts
    3
    Thank you for the replies, especially Jeff Mott for the detailed and on target response. Here is what I've settled on (for now):
    Code:
    var Base_class = Object.create(Object, {
        constructor: { value: function (argument){
            this.property = argument;
            etc();
            return this;
        }},
        method: { value: function(){
            return etc();
        }}
    });
    var Extended_class = Object.create(base_class, {
        constructor: { value: function (arg1, arg2){
            Object.getPrototypeOf(extended_class).constructor.call(this, arg1);
            this.other_property = arg2;
            return this;
        }},
        other_method: { value: function(){
            return etc();
        }}
    });
    var instance = extended_class.constructor.call(Object.create(extended_class), 1, 2);
    alert(instance.property);
    alert(instance.other_property);
    alert(instance.method());
    alert(instance.other_method());
    alert(base_class.isPrototypeOf(extended_class)); // true
    How does this look? I may be writing code for clients pretty soon, so I'm trying to work with conventions that will be understandable for people who may have to maintain my code. In other words, I don't want to look like I haven't touched ECMAscript since back in 2005.

  6. #6
    Join Date
    Jul 2003
    Location
    The City of Roses
    Posts
    2,503
    What's really interesting about this implementation is that it's more prototypal than most JavaScript code. Most JavaScript uses constructor functions to make a prototypal language appear as if it were classical. I think embracing JavaScript's prototypal nature like you've done is a step in the right direction.

    Object instantiation, though, seems a bit verbose. We could probably clean that up with a couple helper methods on the base class.

    Code:
    var Base_class = Object.create(Object.prototype, {
        extend: { value: function (descriptors) {
            return Object.create(this, descriptors);
        }},
        
        create: { value: function () {
            var instance = Object.create(this);
            instance.constructor.apply(instance, arguments);
            
            return instance;
        }},
    
        constructor: { value: function (argument){
            this.property = argument;
            etc();
        }},
        
        method: { value: function(){
            return etc();
        }}
    });
    Then the code we write could look like this:

    Code:
    var Extended_class = Base_class.extend({
        constructor: { value: function (arg1, arg2){
            Object.getPrototypeOf(Extended_class).constructor.call(this, arg1);
            this.other_property = arg2;
            return this;
        }},
        other_method: { value: function(){
            return etc();
        }}
    });
    
    var instance = Extended_class.create(1, 2);
    alert(instance.property);
    alert(instance.other_property);
    alert(instance.method());
    alert(instance.other_method());
    alert(base_class.isPrototypeOf(Extended_class)); // true
    But there are some drawbacks to be aware of. First and foremost, Object.create wasn't implemented in IE until version 9. Depending on what browsers you need to support, this could be a deal breaker.

    Also, even though renowned developers such as Doug Crockford advocate the prototypal style, the pseudo-classical style is nonetheless more common. You'll need to provide plenty of documenting comments and examples so that other developers can easily understand how this code works and how they're supposed to use it.
    for(split(//,'))*))91:+9.*4:1A1+9,1))2*:..)))2*:31.-1)4131)1))2*:3)"'))
    {for(ord){$i+=$_&7;grep(vec($s,$i++,1)=1,1..($_>>3)-4);}}print"$s\n";

  7. #7
    Join Date
    Apr 2012
    Posts
    3
    > But there are some drawbacks to be aware of. First and foremost, Object.create wasn't implemented in IE until version 9. Depending on what browsers you need to support, this could be a deal breaker.

    Ah, yes. This is why I stopped doing web development. I got lured back into it with the promise that client sniffing was a thing of the past.

    According to a quick search, it seems the market share of browsers not supporting Object.create is around 40%. Also, HTML5 canvas isn't supported by those same browsers. In order to do anything, it looks like I'll have to include a lot of shims and workarounds:
    - https://github.com/kriskowal/es5-shi...es5-shim.js#L1
    - http://code.google.com/p/explorercan...canvas.js?r=48
    - etc.

    It looks like the updates that got me back into the game create a language that won't be usable until another decade has gone by. /:
    Is this the general state of things? How do developers generally solve the dilemma of "program to the lowest common set of features" or "program using new features for 20% of clients"? Is there a set of 20 files that I can include in the head of every html document in order to bring my potential viewers up to around N% of the web? (where N is a reasonably high number.)

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center



Recent Articles