Object Oriented JavaScript
Object-Oriented Programming (OOP) is a programming paradigm that emphasizes making sure that the objects in question understand what they can and cannot do. Objects communicate with other objects via the permitted interfaces (public fields and methods), and they adhere to the limitations imposed by the different OOP ideas. At the most basic level, an OOP paradigm provides a class, and you utilize that class to build an instance, which is referred to as the object of that class. A class contains a name, certain properties (fields/states), and methods that interact with the data elements/properties.
Class
Before ES6, developers had to use JavaScript functions to implement classes, but with ECMAScript 2015, the class keyword was formally introduced. This saves some coding time and increases desire to understand and use OOP ideas in JavaScript. While it may appear to be simple syntactic sugar in the form of a predefined function, treating it as a function that might affect the coder’s behavior, let’s call it a highly special function that you should use whenever you need to declare an entity to generate one or more objects of that kind. At its most basic level, a class resembles the following:
class User {
constructor( firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
getFullName() {
return `${this.firstName} ${this.lastName}`;
}
updateName(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
You’ve just created a class containing member variables firstName and lastName, as well as methods getFullName and updateName, which can be used to read/manage the class’s state.
The this keyword is used in the methods to refer to class members like this.
lastName, this.firstName. It grants access to the member’s current instance.
After you’ve defined the class, you may create as many instances of it as you need in your application. A class also expects you to write all of your code in strict mode. The strict mode in JavaScript is a preventative technique of developing code that enforces good coding standards by throwing errors when comparatively risky activities are made (for example, when you try to use undeclared variables).
Constructor
A constructor is required for every class. You may either declare it directly, like in the example above, or you can avoid explicit specification and JavaScript will add an empty and invisible constructor for you. When you explicitly specify a constructor, you may provide it zero or more parameters to use to initialize the member variables. You used an explicit class declaration in the previous class declaration. In some circumstances, a default initialization is quite acceptable. You may set a default value by putting a value in the constructor’s arguments, as demonstrated below:
class User {
constructor(firstName, lastName, email = “test@test.com”) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
getFullName() {
return `${this.firstName} ${this.lastName}`;;
}
updateName(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}user = new User("Brendan", "Eich");
console.log( user.getFullName());
The constructor in the previous code takes just two parameters and utilizes the email’s default value to initialize the matching property.
Static Members
A static member of a class is one that is related at the class level rather than at the level of the object instance. At the class level, a static member has just one instance. Static functions were formerly defined by layering a method or variable on top of a function object. With ES6, JavaScript, on the other hand, gives you an approach that you’d expect in any OOP paradigm. The static keyword may now be used to designate a method as being static. For example, in the following code, you can make use of the create method, which is a static method to create an instance of the User:
class User {
static userCount = 0;
constructor(firstName, lastName, email = “test@test.com”) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
getFullName() {
return `${this.firstName} ${this.lastName}`;;
}
updateName(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
static createUser(firstName, lastName, email = “test@test.com”) {
return new User(firstName, lastName, email);
}
}user = new User("Brendan", "Eich");
console.log( user.getFullName());
newUser = User.createUser("Bjarne", "Stroustrup");
console.log( newUser.getFullName());
The static performs more like what you’d expect in an Object-Oriented paradigm with the idea of class in existence. Instead of calling static methods or variables on the instances, you call them on the class. When you require a utility function or a lifecycle function like create, a static method is usually the best choice. You used the static method to generate a new instance (newUser) from the class in the preceding code sample. You also kept track of the number of instances of the User class using the static member variable userCount.
You used the new operator in the class to generate a new object whenever you require an instance of the class. The constructor of the class is automatically called when a new instance is created to initialize the member variables. For example, when you construct the newUser object, you can do it as follows:
newUser = new User("Brendan", "Eich","test@test.com");
The User class’s constructor will be called automatically using the arguments given to the new operator. If you try to create an object without using the new operator, however, you will get an error. Other methods, on the other hand, lack an internal Construct method, thus you can’t use a new operator on them.
The following code shows a typical usage of the classes in a website:
<!DOCTYPE html>
<html>
<body>
<h2>User Details</h2>
<p id=”name”></p>
<script>
class User {
constructor(firstName, lastName, email = “test@test.com”) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
getFullName() {
return `${this.firstName} ${this.lastName}`;;
}
updateName(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
user = new User("Brendan", "Eich");
document.getElementById(“name”).innerHTML = user.getFullName();
</script>
</body>
</html>
Class Expression
There are situations wherein you can declare a class as an expression. For example, you could need to dynamically return a class from a function or give an anonymous class declaration to a variable. The following code snippet demonstrates how to anonymously construct a class and assign it to a variable that can later be used to make instances of the class:
<script>
let User = class { constructor(firstName, lastName, email = “test@test.com”) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
} getFullName() {
return `${this.firstName} ${this.lastName}`;;
}
updateName(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}}user = new User("Brendan", "Eich");console.log( user.whoAmI() );</script>
Because classes may be specified as expressions, defining a class in JavaScript is essentially the same as evaluating an expression.
While the above code illustrates how to declare a class in an anonymous manner, you can also specify a class name and utilize it within your class.
Encapsulation
By defining the data as private and giving public methods to access and alter the data, encapsulation allows a class to encapsulate data and methods into a single unit and give a mechanism for data concealing. A variable is declared as public by default. You can, however, utilize hash (#) prefixed variable names, where the hash represents a component of the name that will be used as a private variable accessible only from within the class. The following code shows the usage of the public and private variables, including the static private and public variables:
class User {
static userCount = 0;
static #passwordLevel = 1;
#email = “test@test.com”; constructor(firstName, lastName, email) {
this.firstName = firstName;
this.lastName = lastName;
this.#email = email;
User.userCount++;
} getFullName() {
return `${this.firstName} ${this.lastName}`;
} updateName(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
} static createUser(firstName, lastName, email = “test@test.com”) {
return new User(firstName, lastName, email);
} getUserDetails() {
return `Hello. I'm ${firstName.} My email ID is${this.#email} and my Password Level ${User.#passwordLevel}`; }}
user = new User("Brendan", "Eich");
console.log( user.getUserName());
console.log( User.#passwordLevel); // ← This will throw an error because we are trying to access private static variable.
The highlighted code in the preceding code snippet indicates the following:
- You can define public and private members
- Private members, including private static members may only be accessed from within the class.
- By creating a class instance, public variables may be accessed.
- The public static member variables will not be invoked on a specific instance; instead, they may be accessed by using the class name directly.
Inheritance
In OOP, inheritance is a technique that allows you to base your class on an existing class and so inherit all of the properties and methods offered by that class. This increases reusability and reduces work and expense during application development and maintenance. While inheritance in JavaScript was previously complex, the extends keyword may now be used to indicate that a class is derived from a specific base class. The following code sample shows how to construct a derived class using inheritance and the extends keyword:
class User {
constructor( firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
getFullName() {
return `${this.firstName} ${this.lastName}`;
}
updateName(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}class Student extends User {
constructor( firstName, lastName, studentId ) {
super(firstName, lastName);
this.studentId = studentId;
} get studentId() {
return this.studentId;
} set studentId( studentId ) {
this.studentId = studentId;
}
}
You may build an object in the same way you did previously and utilize methods from the derived class to generate the HTML element, as seen in the following code:
student = new Student("Brendan", "Eich","SID22236");
document.getElementById(“name”).innerHTML = student.getFullName();
document.getElementById("studentID").innerHTML = student.studentId;
To call the constructor of the parent class, the derived class expects you to use the super keyword. This makes sense because you don’t want to duplicate the parent class’s initiation logic in the derived class.
If you don’t explicitly specify a constructor in the derived class, JavaScript creates one for you and calls the super keyword, which launches the parent class’s constructor method. If a derived constructor is explicitly defined, it must call the parent constructor by explicitly invoking super in the derived class before accessing this or returning from a derived constructor. Because the super call, even within the constructor, will create the this object, it is critical that you call super before using this to initialize any other member variable.
Method Override
By default, the base class’s methods are made available to the derived class in the same way. However, you may wish to modify the attributes or behavior of some of the methods that were derived from the parent or base class in specific circumstances. A method override is the term for this procedure.
class User {
constructor( firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
getFullName() {
return `${this.firstName} ${this.lastName}`;
}
updateName(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
getDescription() {
return “I am a User!”;
}
}class Student extends User {
constructor( firstName, lastName, studentId ) {
super(firstName, lastName);
this.studentId = studentId;
} get studentId() {
return this.studentId;
} set studentId( studentId ) {
this.studentId = studentId;
} getDescription() {
return “I am a Student!”;
}}