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
?
"My question is Why don't just assign
that.get_name
tosuper_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;
};
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With