views:

232

answers:

1

In Douglas Crockford's JavaScript: The Good Parts he recommends that we use functional inheritance. Here's an example:

var mammal = function(spec, my) {
    var that = {};
    my = my || {};

    // Protected
    my.clearThroat = function() { 
        return "Ahem";
    };

    that.getName = function() {
        return spec.name;
    };

    that.says = function() {
        return my.clearThroat() + ' ' + spec.saying || '';
    };

    return that;
};

var cat = function(spec, my) {
    var that = {};
    my = my || {};

    spec.saying = spec.saying || 'meow';
    that = mammal(spec, my);

    that.purr = function() { 
        return my.clearThroat() + " purr"; 
    };

    that.getName = function() { 
        return that.says() + ' ' + spec.name + ' ' + that.says();
    };

    return that;
};

var kitty = cat({name: "Fluffy"});

The main issue I have with this is that every time I make a mammal or cat the JavaScript interpreter has to re-compile all the functions in it. That is, you don't get to share the code between instances.

My question is: how do I make this code more efficient? For example, if I was making thousands of cat objects, what is the best way to modify this pattern to take advantage of the prototype object?

+2  A: 

Well, you just can't do it that way if you plan on making lots of mammal or cat. Instead do it the old fashioned way (prototype) and inherit by property. You can still do the constructors the way you have above but instead of that and my you use the implicit this and some variable representing the base class (in this example, this.mammal).

cat.prototype.purr = function() { return this.mammal.clearThroat() + "purr"; }

I'd use another name than my for base access and store it in this in the cat constructor. In this example I used mammal but this might not be the best if you want to have static access to the global mammal object. Another option is to name the variable base.

Plynx
The problem with linking the `my` object via the `this.mammal` is that I would then lose the privacy of it, as someone could just do `cat.mammal.clearThroat()` and access the protected method.
cdmckay
So true. If you want privacy then you need to do it by convention, for example, preceding your protected methods with underscores. If that seems too loose, consider that even this "functional inheritance" pattern is itself a convention. Javascript is not a "neat freak" language, it's much more "rough and ready." Making it work the neat freaky way costs a penalty in performance, as you found out. However, don't make too much of the penalty--it takes tens of thousands of object creations to significantly impact your overall run speed, given your example.
Plynx
“someone could just do `cat.mammal.clearThroat()` and access the protected method” — not every problem needs to be solved with code. With the greatest possible respect, you are not writing Windows. If someone misuses your code, that’s awesome, because it means someone’s actually using your code. Much better to focus on making code that’s useful, and easy to use correctly, rather than guarding against hypothetical problems.
Paul D. Waite
@Paul D. Waite: I understand what you're saying, but I'm asking this question more to gain a deeper understanding of JavaScript than anything else.
cdmckay
@cdmckay I come from a functional language background and Javascript is a functional language based on Scheme. In procedural languages with type systems, you need OO semantics in order to express your way around the limitations of the type system. In Javascript, inheritance of this sort is unneeded to create polymorphism--there is no type system and so no need to express to the codebase that A is a type of B. Instead any two objects that share a set of properties can be treated as polymorphous. To share code, you can directly mix in code via prototypes and function references.
Plynx
@cdmckay: ah yes, I did go off on a bit of a rant there.
Paul D. Waite