Encapsulation is a concept that allows the use of an object without having to know its internal implementation in detail. The interaction with an object is done only via its public interface, which contains public members and methods. We can say that encapsulation allows an object to be treated as a "black box", separating the implementation from its interface. Think of the objects you've worked with so far: document, a DOM object, and xmlHttp, an
XMLHttpRequest object. You certainly don't know how these objects do their work internally! All you have to know is the features you can use.
The "features you can use" of a class form the public interface of a class, which is the sum of all its public members. The public members are those members that are visible and can be used by external classes. For example, the
innerHTML property of a DOM object (such as the default document object), or the
send() methods of
XMLHttpRequest, are all public, because you were able to use them. Each class can also contain
private members, which are meant for internal usage only and aren't visible from outside.
Inheritance allows creating classes that are specialized versions of an existing class. For example assume that you have the Car class, which exposes a default interface for objects such as myCar, johnsCar, or davesCar. Now, assume that you want to introduce in your project the concept of a supercar, which would have similar functionality to the car, but some extra features as well, such as the capability to fly!
If you're an OOP programmer, the obvious move would be to create a new class named SuperCar, and use this class to create the necessary objects such as mySuperCar, or davesSuperCar. In such scenarios, inheritance allows you to create the SuperCar class based on the Car class, so you don't need to code all the common features once again. Instead, you can create SuperCar as a specialized version of Car, in which case SuperCar inherits all the functionality of Car. You would only need to code the additional features you want for your SuperCar, such as a method named Fly. In this scenario, Car is the base class (also referred to as superclass), and SuperCar is the derived class (also referred to as subclass).
Inheritance is great because it encourages code reuse. The potential negative side effect is that inheritance, by its nature, creates an effect that is known as tight coupling between the base class and the derived classes. Tight coupling refers to the fact that any changes that are made to a base class are automatically propagated to all the derived classes. For example, if you make a performance improvement in the code of the original
Car class, that improvement will propagate to
SuperCar as well. While this usually can be used to your advantage, if the inheritance hierarchy isn't wisely designed such coupling can impose future restrictions on how you can expand or modify your base classes without breaking the functionality of the derived classes.
Polymorphism is a more advanced OOP feature that allows using objects of different classes when you only know a common base class from which they both derive. Polymorphism permits using a base class reference to access objects of that class, or objects of derived classes. Using polymorphism, you can have, for example, a method that receives as parameter an object of type
Car, and when calling that method you supply as parameter an object of type
SuperCar is a specialized version of
Car, all the public functionality of
Car would also be supported by
SuperCar, although the
SuperCar implementations could differ from those of
Car. This kind of flexibility gives much power to an experienced programmer who knows how to take advantage of it.