Object-Oriented JavaScript: Part 3 | Page 2
[previous] [next]
Object-Oriented JavaScript: Part 3
Inheritance using Closures and Prototypes
There are two significant techniques for implementing the OOP concept of inheritance with JavaScript code. The first technique uses closures, and the other technique makes use of a feature of the language named prototyping.
Early implementations of the Microsoft AJAX library made use of closures-based inheritance, and in the final stage the code was rewritten to use prototypes. In the following few pages we'll quickly discuss both techniques.
Inheritance Using Closures
In classic OOP languages such as C#, C++, or Java, you can extend classes through inheritance. Closure-based inheritance is implemented by creating a member in the derived class that references the base class, and calling that member. This causes the derived class to inherit all the base class members, effectively implementing the concept of inheritance.
To demonstrate this technique, we'll implement two classes: Car
and SuperCar
. The Car
class constructor receives a car name as parameter, and it has a method named Drive()
. The class SuperCar
inherits the functionality of Car
, and adds a new method named Fly()
, reflecting the additional functionality it has in addition to what Car
has to offer. The diagram in Figure 3-6 describes these two classes.
Remember that in JavaScript the implementation of a class diagram can be achieved in multiple ways. The code reflects the concept of the diagram, but not also the implementation details, as the C# code would. Here's a possible implementation of Car
and SuperCar
:
Loading this script in a browser would generate the results shown in Figure 3-7. It can be tested online.
The exercise demonstrates that inheritance really works. SuperCar
only defines the capability to Fly()
, yet it can Drive()
as well. The capability to Drive()
and the Name
property are inherited from Car.
At the first sight the code can look a bit complicated, especially if you're a C# veteran. The Drive()
and Fly()
functions aren't defined inside Car
and SuperCar
, as you'd do in a C# class. Instead, we stored these methods/functions in the global context, and referenced them in Car
and SuperCar
, to avoid the memory leaks that were discussed earlier in this chapter. You can, however, define Drive()
inside Car
, and Fly()
inside SuperCar
, without losing any functionality.
If you comment the execution of this.inheritsFrom(name)
from SuperCar
, it won't inherit the capabilities of Car
any more. If you make this test in FireFox, you'll see the following eloquent error message in the Error Console window of Firefox:
The problem with the presented inheritance solution is that it's not very elegant. Writing all functions and classes in the global context can quickly degenerate into chaos; and things get even more complicated if you want to have classes that have functions with the same name. Needless to say, this isn't something you need to be dealing with when writing your code. Luckily, JavaScript has a very neat feature that allows us implement inheritance in a much cleaner way: prototyping.
Inheritance Using Prototyping
Once again, prototyping can help us implement an OOP feature in a more elegant way than when using closures. Prototype-based inheritance makes use of the behavior of JavaScript prototypes. When accessing a member of a function, that member will be looked for in the function itself. If it's not found there, the member is looked for in the function's prototype. If it's still not found, the member is looked for in the prototype's prototype, and so on until the prototype of the implicit Object
object.
In closure-based inheritance, the derived class inherits the base class methods and properties by "loading" them into itself. Here's the code again for your reference:
When implementing inheritance through prototyping, we can "load" the base class properties and methods by adding them to the derived class prototype. That way, an object of the derived class will have access to the class methods and properties, but also to the base class methods and properties since they exist in the derived class prototype. To successfully implement prototype-based inheritance with JavaScript, you need to:
|
This is so very complicated! In practice you'll find that the code doesn't look that scary, although the complete theory is a little more complex than this. A nice article describing a few additional theoretical aspects can be found at https://mckoss.com/jscript/object.htm.
The new implementation of Car
and SuperCar
, this time using prototypes, is the following, with the inheritance mechanism highlighted. The Drive()
and Fly()
methods have also been created through prototyping, although the old version using closures would work as well. The code can be checked online at https://www.cristiandarie.ro/seo-asp/JavaScriptPrototypeInheritance.html.
Here, instead of creating a Car
instance in SuperCar
's constructor, we declare Car
as SuperCar
's prototype.
[previous] [next]
URL: