OOP Javascript
OOP in JavaScript is dynamic, meaning it doesn't provide a native class implementation.
In JavaScript, the OOP (Object-Oriented Programming) implementation can be seen as a tree-like structure of objects, with the global object at the root. All objects inherit from a common ancestor, typically Object.prototype
. When a new object or function is created, it inherits properties and methods through the prototype chain, which resembles branches connecting objects to their parent objects (prototypes). This prototype chain forms the inheritance hierarchy, with the global object (like window
in browsers) serving as the base ancestor in this structure.
The class
keyword is introduced in ES2015 (ES6) just as a form of syntactical sugar. Apart from that, JavaScript remains prototype-based.
Of course, it does implement OOP principles such as:
Encapsulation: Bundling data (properties) and methods within objects, limiting access to certain properties using closures or private fields.
Abstraction: Hiding the complexity of an object's internal implementation while exposing only necessary details via methods.
Inheritance: Objects can inherit properties and methods from other objects through prototypes, allowing reuse of code.
Polymorphism: Objects can share a method name but implement it differently, allowing for different behaviors based on the object type.
Implementation
OOP in JavaScript has various implementation techniques, with the same "under the hood" behavior:
Object.create()
Constructor Functions
ES6 Classes
Prototypal inheritance
Object.create()
Object.create()
takes advantage of the prototypal nature of JavaScript. It takes an optional object argument which will be the prototype of the new object, without storing the same methods twice.
Constructor Functions
Constructor functions achieve the same thing, but the use of the new
keyword "automates" some operations such as removing the need for the return
statement.
Classes
Classes in JavaScript achieve the same thing as above but have been mainly introduced as syntactic sugar as they are easier to read and write.
In this example of ES6 classes, the Elf
class defines a constructor for setting up instances with name
and weapon
properties. The attack()
method is defined on the prototype, meaning it’s shared among all instances (like sam
and peter
), saving memory because the method is stored only once. The attack()
method can be called by any Elf
instance, but it’s not an instance property, which is why hasOwnProperty('attack')
returns false. This demonstrates how JavaScript's class-based inheritance manages memory efficiently.
JavaScript introduced private fields in ES2022, providing true privacy in classes. These private fields are prefixed with a #
symbol and are only accessible within the class they are declared in. For example:
Here, #privateField
is only accessible within the Example
class and cannot be accessed or modified directly from outside. This allows for proper encapsulation and data hiding in JavaScript OOP.
Inheritance and polymorphism
In this example, inheritance is demonstrated by the Elf
and Ogre
classes extending the Character
class, allowing them to inherit properties (name
, weapon
) and methods like attack()
from Character
. The super()
call in their constructors initializes the parent class.
Polymorphism is shown by the Ogre
class overriding the attack()
method with its own version (aaargh
), allowing the Ogre
class to behave differently when the attack()
method is called. The Elf
class, on the other hand, uses the inherited attack()
method as-is.
Last updated
Was this helpful?