I'm learning the different inheritance implementations in javascript, mostly following the Javascript Patterns book by Stoyan Stefanov.
Now I was inspecting how Coffescript implements it. So given a parent and a child classes or constructors:
class Animal
constructor: (@name) ->
move: (meters) ->
alert @name + " moved #{meters}m."
class Snake extends Animal
move: ->
alert "Slithering..."
super 5
sam = new Snake "Sammy the Python"
sam.move()
They are compiled to:
var Animal, Horse, Snake, sam,
_extends = function(child, parent) {
for (var key in parent) {
if (_hasProp.call(parent, key)) child[key] = parent[key];
}
function ctor() {
this.constructor = child;
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
child.__super__ = parent.prototype;
return child;
},
_hasProp = {}.hasOwnProperty;
Animal = (function() {
function Animal(_name) {
this.name = _name;
}
Animal.prototype.move = function(meters) {
return alert(this.name + (" moved " + meters + "m."));
};
return Animal;
})();
Snake = (function(_super) {
_extends(Snake, _super);
function Snake() {
return Snake.__super__.constructor.apply(this, arguments);
}
Snake.prototype.move = function() {
alert("Slithering...");
return Snake.__super__.move.call(this, 5);
};
return Snake;
})(Animal);
sam = new Snake("Sammy the Python");
sam.move();
As I've understood the implementation of the inheritance in coffescript result from the combination of different patterns:
1. The Classical proxy Constructor
In this case we we also reset the constructor pointer and store the Superclass reference. What Stefanov defines 'Holy Grail'.
With this pattern the child only inherits properties of the prototype.
// the proxy function
function ctor() {
this.constructor = child;
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
child.__super__ = parent.prototype;
2. The Inheritance by Copying Properties
With this pattern we simply copy the properties of one object into another
_hasProp = {}.hasOwnProperty;
for (var key in parent) {
if (_hasProp.call(parent, key)) child[key] = parent[key];
}
3. Classical Pattern - Rent-a-Constructor (or Borrow a Constructor)
function Snake() {
return Snake.__super__.constructor.apply(this, arguments);
}
QUESTION:
- Are my assumptions correct? Is coffescript compiler using 1+2+3?
- The inheritance by copying seems to use a shallow copy, meaning that it is not inspecting to check if the property is an object/array and starting a recursion. Even tough the result seems a perfect deep copy (objects/arrays are copies, not references). Why/how?
- Isn't the rent-a-constructor creating a repetition of the inheritance? Properties copied and then parent constructor called again?
- Can the
_extendsfunction also be used between objects instead of Constructors?
Thanks