The accepted answer will definitely do the trick. And this "short" explanation turned into a ramble, but hopefully it's helpful.
There's one thing you have to be aware of with the accepted answer. When basically "inheriting" by doing Bar.prototype = new Foo()
you're calling the constructor. So, if you have code in your constructor that isn't expecting to be used as a launch pad for another "class" you'll wind up with weird effects. Take for instance:
var Person = function (firstName, lastName) {
....
};
var Student = function (firstName, lastName, grade) {
....
};
Let's say that Student
is an extension of Person
. How are you going to build the prototype up on Student
? Probably not like Student.prototype = new Person("John", "Doe");
A different way of handling it, which is a bit more complex but can be wrapped inside of another function is as follows:
var extend = function (child, parent) {
var f = function () {};
f.prototype = parent.prototype;
child.prototype = new f();
child.prototype.constructor = parent;
}
var Person = function (firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Person.prototype.getName = function () {
return this.firstName + " " + this.lastName;
}
Person.prototype.setAge = function (age) {
this.age = age;
}
var Student = function (firstName, lastName, grade) {
Person.call(this, firstName, lastName);
this.grade = grade;
};
extend(Student, Person); //<< do this before adding stuff to the prototype
Student.prototype.getName = function () {
var name = Person.prototype.getName.apply(this);
return name + ", Grade " + this.grade;
}
Student.prototype.tooOldToBeAStudent = function () {
if(this.age > 18) { return true; }
}
var p = new Person("Joe", "DiMaggio");
var s = new Student("Jack", "Sparrow", 12);
console.log(p.getName(), s.getName());
//consoles "Joe DiMaggio" "Jack Sparrow, Grade 12"
console.log(s instanceof Person);
//true - even with the weird looking inheritance, Student is still an instance of Person.
s.setAge(30);
console.log(s.age);
//30, just like what you'd expect with a Person object.
console.log(s.tooOldToBeAStudent);
//true - as mentioned previously, 'age' is set via its inherited method.
This gets you not only the Person functionality, but allows you to build on it. Kind of like what you actually do with inheritance.
How does it work? Great question. First, objects are assigned around [basically] by reference. The prototype is an object. So, in the extend
function, I create a blank function that will serve as the surrogate for the child
. This copies the parent
's prototype to itself, and then makes a new instance of itself the prototype of the child
. This way the parent
's constructor isn't called, but the parent's prototype is still used. To make sure that instanceof
still works, the child.prototype.constructor
is set to the parent
- effectively informing javascript that the thing the child came from is the parent, rather than from the surrogate.
Also, when overriding methods, you can use the "class" you are inheriting from's prototype method and apply
or call
it with this
- that runs the method with the scope of the current object, and you can pass any arguments you feel like however they are accepted by the function you choose. For example, Person.prototype.getName.apply(this);
runs the Person's getName
in the context of the current instance of the student. Let's say we wanted to override the setAge to simply console.log out the age.
Student.prototype.setAge = function () {
Person.prototype.setAge.apply(this, arguments);
console.log(this.age);
}
What's happening here is the Person
's setAge
is being called with the arguments that were passed to the Student
's setAge
. So, it basically allows the stuff to pass through without you having to know about the details of the original method's arguments.