Using super methods in Javascript based on Crockford functional inheritance

I read the chapter on functional inheritance at Crockford, The Good Parts. In the mammal example, he gives me a little embarrassment as to why he uses the superior method to change the get_name function. Here is the example in question:

 Function.prototype.method = function (name, func) { this.prototype[name] = func; return this; }; var mammal = function (spec) { var that = {}; that.get_name = function () { return spec.name; }; that.says = function () { return spec.saying || ''; }; return that; }; var myMammal = mammal({ name: 'Herb' }); var cat = function (spec) { spec.saying = spec.saying || 'meow'; var that = mammal(spec); that.purr = function (n) { var i, s = ''; for (i = 0; i < n; i += 1) { if (s) { s += '-'; } s += 'r'; } return s; }; that.get_name = function () { return that.says() + ' ' + spec.name + ' ' + that.says(); }; return that; }; Object.method('superior', function (name) { var that = this, method = that[name]; return function () { return method.apply(that, arguments); }; }); var coolcat = function (spec) { var that = cat(spec); var super_get_name = that.superior('get_name'); that.get_name = function (n) { return 'like ' + super_get_name() + ' baby'; }; return that; }; var myCoolCat = coolcat({ name: 'Bix' }); var name = myCoolCat.get_name(); // 'like meow Bix meow baby' 

I am confused by this because I can replicate the same thing by removing the superior method and simply modifying coolcat as follows:

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

So, I donโ€™t understand why Crockford chooses the superior method. Can anyone explain at all?

+4
source share
2 answers

The idea here is:

 var super_get_name = that.superior('get_name'); 

makes super_get_name function that - every time it is called - calls that original get_name method. This allows the new get_name call the old (superclass) get_name .

Now, if the original get_name method never has any effect, except to return one value that will never change, then yes, it is completely pointless; you can just save one value that never changes and then use it in the new get_name . But if the original get_name can really do something (for example, run an AJAX request or change the style of the HTML element) or change its return value (say, if there is an appropriate set_name ), then there will be an important difference between what your code does (save the original return value and use it) and what Crockford code does (save the original method and call it).

+4
source

The confusion arising from this chapter of Crockford's book arises, as Crockford describes, โ€œhisโ€ preferred pattern for implementing inheritance in JavaScript, which relies on his extension of the Function object with Function.prototype.method (chapter 1.3), which he uses to add methods to the Function object.

The problem discussed in the coolcat example is the need to access the parent type method. In "classic" OO languages, such as Java, this is natural because classes exist by themselves. In JavaScript, inheritance is prototyped, you create an object of type mammal , and then modify the object to create type cat or coolcat .

Depending on your design, you can add properties and functions or redefine the inherited function. The problem arises when you redefine an โ€œinheritedโ€ function, in JavaScript you basically replace the old function with the new function, thereby losing the older function.

Crockford must now do two things:

  • get the parent (cat's) get_name ; and
  • save it in a way that can be used from an overridden method.

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

He does 1. by calling the superior method to get the function that gets the cat function get_name ; and he does 2. by storing it in the super_get_name variable in the coolcat (/ object) function, giving access to the cat get_name function before it is redefined (more correctly rewritten) using the coolcat get_name function.

In my opinion, the confusion arises from the fact that:

  • The superior method is called strange: the superior method is just a method for searching by name and can be better named, for example, as getFunctionByName (you can try replacing get_name with purr , coolcat get_name will now call purr, just remember to name it as super_get_name(10) , otherwise you will get an empty string).
  • Secondly, the code and the pattern trick the code into relying on some specific Crockford patterns, and you will probably be reproached if you try to dive into this chapter without following the entire book.

I think there is an easier way to achieve this, one that I think, because it is completely localized, easier to understand, etc., as in the code below:

 var coolcat = function(spec) { var that = cat(spec); that.parent_get_name = that.get_name; that.get_name = function() { return 'like ' + this.parent_get_name() + ' baby'; }; return that; }; 

There are some other oddities, such as the argument n in the definition of the coolcat get_name function, which I can only assume when copying the purr function that the ghost writer would suggest!

Finally, I would suggest that before you read the book, you need to listen to his talk about "JavaScript good parts." The conversation is absolutely brilliant, much better than a book.

+3
source

Source: https://habr.com/ru/post/1400755/


All Articles