Question

In the functional inheritance pattern, Crockford introduces a new superior method via:

Object.method('superior', function (name) {
    var that = this,
    method = that[name];
    return function () {
        return method.apply(that, arguments);
    };
});

Where method is :

Function.prototype.method = function (name, func) {
    this.prototype[name] = func;
    return this;
};

Example:

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;
};

My question is Why don't just assign that.get_name to super_get_name ?

Was it helpful?

Solution

"My question is Why don't just assign that.get_name to super_get_name?"

Because the way the get_name method has its this value set to the that object is by invoking it as:

that.get_name();

When a function is invoked as the method of an object, the object becomes the value of this in that invocation of the function.

If you had done this instead:

var super_get_name = that.get_name;

super_get_name();

Now you're invoking a detached function, so it doesn't know what its this value should be, and so it uses the default, which is usually the window object.


I don't like the solution that crockford shows at all. Typically, in that situation, you'd simply make a new function right there instead of relying on extensions to Object.prototype to do it for you. (Extending Object.prototype is very ugly IMO.)

var coolcat = function (spec) {
    var that = cat(spec),
        _original_get_name = that.get_name,
        super_get_name = function() {
                             return _original_get_name.apply(that, arguments);
                         };

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

Or in modern implementations, you'd use Function.prototype.bind to create a new function with its this value bound to whatever you provided as the first argument to .bind().

var coolcat = function (spec) {
    var that = cat(spec),
        super_get_name = that.get_name.bind(that);

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

OTHER TIPS

In the sense of Crockford's Functional Inheritance Pattern it is completely valid to reference the base class method

var super_get_name = that.get_name;

This is how Crockford teaches it in his lecture JavaScript Master Class , see the part on Functional Inheritance.

Later - the method might be overriden by the derived class - you invoke it simply

super_get_name();

Crockford's superior method makes no sense in the Functional Inheritance Pattern.

Because in my opinion this is never needed in a method defined by a producer function. If you use this in your methods you'll run in all sorts of trouble because of dynamic scoping and manipulation of this:

function mammal(spec){
    var that = {};
    that.legs = Math.round(Math.random() * 4);
    that.get_name = function(){
        return spec.name + "with" + that.legs; // always use that not this
    };
    that.isProperThis = function(){
        console.log( this === that );
    };
    return that;
};
var myMammal = mammal({name: 'Herb'});
myMammal.isProperThis(); // true
myMammal.isProperThis.call(window); // false
setTimeout(myMammal.isProperThis, 1); // false

If you insist on using this in your methods you can no longer treat them as "first-class" variables in JavaScript. Instead you have to convert them to "binders" by calling bind as described in the first answer in this post.

superior is a method defined in the prototype of the Object constructor function. It caches an object's method, so that it returns the original method even if it were changed later.

From JavaScript: The Good Parts, p.54:

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

The accepted answer given by cookie monster is correct, but I would like to add clarification.

As cookie monster says, if you write

var super_get_name = that.get_name;

invocation of super_get_name will no longer bind any value to this, making it an unbound function.

However, in the case of the example Crockford gives in The Good Parts, it would not matter if super_get_name were unbound by writing it in the way you propose, because this would never be used in its invocation.

You would essentially end up doing the following:

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

(where the right operand executes in the context of the function assigned to cat).

I assume that Crockford avoids unbound functions here to demonstrate a general principle, even though his specific example does not require binding.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top