2

In Douglas Crockford's "JavaScript: The Good Parts", he walks through three types of inheritance: classical, prototypal, and functional. In the part on functional inheritance he writes:

"The functional pattern also gives us a way to deal with super methods."

He then goes on to implement a method named "superior" on all Objects. However, in the way he uses the superior method, it just looks like he is copying the method on the super object for later use:

// crockford's code:
var coolcat = function(spec) {
    var that = cat(spec),
        super_get_name = that.superior('get_name');
    that.get_name = function (n) {
        return 'like ' + super_get_name() + ' baby';
    };
    return that;
};

The original get_name method is copied to super_get_name. I don't get what's so special about functional inheritance that makes this possible. Can't you do this with classical or prototypal inheritance? What's the difference between the code above and the code below:

var CoolCat = function(name) {
    this.name = name;
}

CoolCat.prototype = new Cat();

CoolCat.prototype.super_get_name = CoolCat.prototype.get_name;
CoolCat.prototype.get_name = function (n) {
    return 'like ' + this.super_get_name() + ' baby';
};

Doesn't this second example provide access to "super methods" too?

3 Answers 3

4
var coolcat = function(spec) {
    var that = cat(spec),
        super_get_name = that.superior('get_name');

    that.get_name = function (n) {
        return 'like ' + super_get_name() + ' baby';
    };

    return that;
};

var cat = coolcat({ ... });

Can just as well be done with prototypes

var CoolCat = {
    constructor: function () {
        Cat.constructor.apply(this, arguments);
        return this;
    },
    getName: function () {
        return 'like ' + Cat.getName() + ' baby';
    }
};

var cat = Object.create(CoolCat).constructor({ ... });

Of course the main difference here is that your not creating two new functions every time you invoke coolcat. coolcat creates a new function for get_name and a new function for super_get_name and basically wastes memory left and right.

One may argue coolcat has privacy but it does not because anyone can call cat({}).superior('get_name'); and get your "private" method.

Of course if one wants privacy and prototypes that's perfectly possible, using the klass macro as shown in the article

var Cat = klass(function (privates) {
    return {
        constructor: function (name) {
            privates(this).name = name; 
        },
        getName: function () {
            return privates(this).name;
        }
    };
});

var CoolCat = klass(Cat, function (privates, $super) {
    return {
        constructor: function () {
            $super.constructor.apply(this, arguments);
        },
        getName: function () {
            return 'like ' + $super.getName.call(this) + ' baby';
        }
    };  
});

var cat = new CoolCat("someName");
console.log(cat.getName());

Live Example

Here we achieve both privacy and super class inheritance in an "elegant" manner.

In this elegant means not having the closure overhead of multiple functions per object (we still add a single closure per object for the privates function) and also allowing normal prototypical OO to just work.

9
  • In your klass gist, what is the "pd" object?
    – kindohm
    Commented Jan 20, 2012 at 15:16
  • Ah, found it in the longer article you linked to.
    – kindohm
    Commented Jan 20, 2012 at 15:20
  • @kindohm I've updated the gist to actually link to pd.
    – Raynos
    Commented Jan 20, 2012 at 15:22
  • in your snippet just below "Can just as well be done with prototypes", this assumes that Cat is a function, and not strictly an object, correct? Otherwise Cat.apply is undefined within CoolCat.constructor. Objects (not functions) do not have an apply() method, correct?
    – kindohm
    Commented Jan 20, 2012 at 21:14
  • @kindohm I made the mistake of of doing Cat.apply instead of Cat.constructor.apply. Non-callable functions do not have a generic apply method
    – Raynos
    Commented Jan 20, 2012 at 21:39
1

It's a great question about a great book. The book takes a couple of readings to be fully digested. I came across this question, while researching some subtleties of javascript based on the book. I've basically had the same question, but after some pondering, I think that both kindohm's own and Raynos answers are incomplete.

I think kindohm is right that the reason is related to privacy and access, but it is not because the super method is private with the functional approach, as Raynos rightly points out.

On the other hand Raynos's answer sounds almost like there is a mistake in the book, as Raynos offers a different solution than the one that the book gives.

But I think that the solution given in the book still has its place. I think that the main reason/justification for it is in the paragraph preceding the code for the 'superior' method:

The function will invoke the original method even if the property is changed

This is the difference between the functional approach and the pseudo-classical approach that is given as an example in the original question.

It is not a perfect privacy but it gives an additional layer of isolation.

-1

The answer is public versus private. With the functional approach, super methods can be kept private to the object. The second example (using prototype) exposes the super method publicly.

2
  • 1
    It's perfectly fine to post your own answer on your question, as a tip give it a few more hours next time. You answered almost immediately, and that may be perceived as trying to rep up a sockpuppet account. So next time, just wait a few hours, even a couple of days, and possibly give a longer answer. Nothing wrong with this answer, as your network profile shows that you have been contributing a lot on StackOverflow, obviously not a sockpuppet, but it was the first thing that came to mind when I saw your question, so I thought I'd share.
    – yannis
    Commented Jan 20, 2012 at 6:38
  • You don't need the functional approach to do privacy.
    – Raynos
    Commented Jan 20, 2012 at 7:32

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.