Searching over the internet I'm always bumping on this approach of Javascript classes extension
function extend(Child, Parent) {
var F = function() { }
F.prototype = Parent.prototype
Child.prototype = new F()
Child.prototype.constructor = Child
Child.superclass = Parent.prototype
}
But how is that different from this one?
function extend(Child, Parent) {
var p = new Parent()
Child.prototype = p
Child.prototype.constructor = Child
Child.superclass = p
}
This last one also works perfect. So why should I use this extra var F = function() { }
move then?
Invoking the original constructor directly can have undesirable side effects, like not working properly if certain expected arguments are not passed.
That's why they use a "proxy" function, which lets you get a new object that inherits from Parent()
without actually invoking Parent()
.
Here's a simple example:
function Person(name, age) {
if (name === undefined)
throw "A name is required";
this.name = name + "";
this.age = age;
}
If Person
is the parent, it'll throw an error because there was no name
passed.
The first example is (as cookie monster mentioned in the comment) a shim for the following piece of code which might be easier to understand.:
function extend(Child, Parent) {
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
Child.superclass = Parent.prototype;
}
Basically, this implementation makes the object that all Child instances inherit from (Child.prototype) inherit from the object that all Parent instances inherit from (Parent.prototype). Intuitively this is the most accurate representation of class inheritance JavaScript provides.
The second implementation of extends is flawed, because all Child instances will inherit from a specific Parent instance. Should there be significant differences between Parent instances (due to the parameters passed to the constructor for example), the Child instances can not accurate represent that, because they all inherit from a Parent instance created by calling the Parent constructor with no arguments.
Here is an example of what the first implementation can do and the second one can not:
function Parent(name, age) {
this.name = name;
this.age = age;
}
Parent.prototype.greet = function() { return 'I am parent ' + this.name; }
function Child(name){
Parent.call(this, name, 20); // notice the call to the superclass
}
extend(Child, Parent);
Parent.prototype.greet = function() { return 'I am child ' + this.name + ' and i\'m ' + this.age; }
var c = new Child('Tom');
console.log(c.greet()); // I am child Tom and i'm 20
As a sidenote, in the Child constructor i have called the Parent constructor. This is actually quite common when dealing with classical inheritance, so that's another point for the first implementation. It isn't actually required, the Child constructor can safely ignore calling the Parent constructor, but keep in mind that that call basically ensures that the new object created is a valid Parent instance before being a child Instance. In my example if you were to not call the Parent constructor, the name and age properties would not be set on the Child instance, so the greet method would return I am child undefined and i'm undefined
, far from what you would expect.
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