Javascript’s method of object inheritance causes a lot of confusion, even amongst experienced programmers. This is largely because it doesn’t follow the classical inheritance pattern found in many other popular programming languages, suce as Java, PHP, Python and Ruby.
Instead, Javascript uses a prototype inheritance pattern, which is a little different. To confuse matters, many frameworks attempt to “fix” Javascript inheritance by making it work more like classical inheritance. The end result is a mess.
Thankfully, Javascript inheritance is actually pretty easy!
Defining a new class
Let’s define a new class, Animal
. Animals have a name, an age, and can make a noise.
1 2 3 4 5 6 7 8 9 10 |
|
You can instantiate an Animal
like this:
1 2 |
|
Inheriting from this class
Let’s now make a Dog
, which is like an animal, but also has a breed, and makes a different noise.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
You can then instantiate a Dog
like this:
1 2 |
|
What about private methods and properties?
While it’s possible to implement something similar to private methods and properties, it probably isn’t worth the time and effort (and performance penalty) of using them. Simply prefixing non-public methods and properties with an underscore is a good way of indicating they they’re not part of the public API.
What about interfaces?
Interfaces can be useful, but Javascript doesn’t support them. In any case, they would add to the download size of your code.
What about prototype.constructor
?
If your code depends on prototype.constructor
being set, then you can use the following helper method instead of calling Object.create()
directly.
1 2 3 4 5 6 7 8 9 10 |
|
In reality, prototype.constructor
isn’t very useful, so it’s probably best to just call Object.create()
directly.
Using inheritance in your code
Javascript code has an unfortunate habit of turning into a mess of nested callbacks and copy-and-paste logic. Defining a hierarchy of helper classes is just one of the many techniques that allow you to write modular, maintainable code.
For example, consider building:
- A hierarchy of Javascript form validation classes. These could all inherit from a base
Validator
class that implements basic checks for required fields. Subclasses could provide integer validation, date validation, password length validation, etc. - A set of models that map to server-side database objects. These could all inherit from a common
Model
class that contains the HTTP syncronization logic. - A related set of AngularJS services. Data-driven services could inherit from a base
Service
class that provides logic for updating data within bound scopes.