This chapter delves into the world of classes in JavaScript, providing a comprehensive guide from fundamental concepts to advanced applications. Classes, introduced in ES6 (ECMAScript 2015), offer a structured approach to object-oriented programming (OOP), promoting code reusability, organization, and maintainability.
This section lays the groundwork by explaining how objects were created in JavaScript before the introduction of classes in ES6 (ECMAScript 2015). Two main methods were used:
{}
are used to define an object.this
keyword, which refers to the current object instance.
console.log("helloword")const person = {
name: "Alice",
age: 30,
greet: function() {
console.log("Hello, my name is " + this.name);
}
};
person.greet(); // Output: "Hello, my name is Alice"
{}
are used to define an object named person
.name
, age
) and a method (greet
) are assigned directly to the object.greet
method is a function defined within the object itself.person.greet()
is called, the greet
function is executed, printing the greeting message using the this
keyword to access the name
property.this
refers to the newly created object.this
within the constructor function, initializing the object’s state.new
keyword is used to call the constructor function and create a new object instance.
function Person(name, age) {
this.name = name;
this.age = age;
this.greet = function() {
console.log("Hello, my name is " + this.name);
};
}
const alice = new Person("Alice", 30);
alice.greet(); // Output: "Hello, my name is Alice"
Person
acts as a constructor, taking arguments (name
, age
) to represent the object’s initial state.this
refers to the newly created object.name
, age
) and a method (greet
) are assigned to this
.new
keyword is used to create a new object (alice
) from the Person
constructor, passing the arguments to initialize its properties.alice.greet()
is called, the greet
method defined within the Person
constructor is executed for the specific alice
object, printing the greeting with her name.This section introduces classes, a more structured approach to object-oriented programming (OOP) in JavaScript. Classes provide a blueprint for creating objects with shared properties and methods.
class
keyword is used to define a class.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log("Hello, my name is " + this.name);
}
}
const alice = new Person("Alice", 30);
alice.greet(); // Output: "Hello, my name is Alice"
class
keyword is used to define a class named Person
.constructor
method is a special function that is called whenever a new object (instance) is created from the class.name
, age
) are assigned to this
, which refers to the newly created object.greet
method is defined outside the constructor but within the class. This method can access the object’s properties defined in the constructor.alice
) is created using new Person("Alice", 30)
. This calls the constructor
to initialize alice
with the provided name and age.alice.greet()
is called, the greet
method defined in the Person
class is executed on the alice
object, accessing its specific name
property.Classes can inherit properties and methods from parent classes, promoting code reuse and creating hierarchies of related objects:
extends
keyword.
class Employee extends Person {
constructor(name, age, title, salary) {
super(name, age); // Call the parent class constructor
this.title = title;
this.salary = salary;
}
getSalary() {
console.log("Salary: $" + this.salary);
}
}
const bob = new Employee("Bob", 35, "Software Engineer", 80000);
bob.greet(); // Output: "Hello, my name is Bob"
bob.getSalary(); // Output: "Salary: $80000"
Employee
class inherits from the Person
class using the extends Person
syntax.constructor
of the Employee
class calls the parent class constructor (super(name, age)
) to ensure that inherited properties like name
and age
are initialized for Employee
objects.Employee
class adds its own properties (title
, salary
) and a new method (getSalary
).bob
) is created from the Employee
class, inheriting properties and methods from Person
.bob
can access inherited methods (greet
) and its own methods (getSalary
).Classes can define static methods and properties that are accessible without creating an object instance:
MathUtils.add
), not through object instances.
class MathUtils {
static add(x, y) {
return x + y;
}
static PI = 3.14159;
}
console.log(MathUtils.add(5, 3)); // Output: 8
console.log(MathUtils.PI); // Output: 3.14159
MathUtils
class defines two static members:static add(x, y)
: This is a static method accessible using the class name (MathUtils.add
). It takes two arguments and returns their sum.static PI = 3.14159
: This is a static property accessible using the class name (MathUtils.PI
). It holds the value of pi.
class Person {
constructor(name) {
this._fullName = name; // Private property (convention)
}
get fullName() {
return this._fullName;
}
set fullName(newName) {
if (newName.trim() === "") {
console.error("Name cannot be empty");
} else {
this._fullName = newName;
}
}
}
const person = new Person("Alice Bob");
console.log(person.fullName); // Output: "Alice Bob"
person.fullName = ""; // Error: Name cannot be empty
person.fullName = "Charlie Brown";
console.log(person.fullName); // Output: "Charlie Brown"
Person
class has a private property (_fullName
) using the naming convention (starts with an underscore).get fullName
method allows retrieving the value of _fullName
.set fullName
method validates the new name before assigning it to _fullName
. This enforces data validation rules.Mixins are reusable modules that contain functionality you can “mix in” to multiple classes. They promote code reusability and separation of concerns.
class Person {
constructor(name) {
this._fullName = name; // Private property (convention)
}
get fullName() {
return this._fullName;
}
set fullName(newName) {
if (newName.trim() === "") {
console.error("Name cannot be empty");
} else {
this._fullName = newName;
}
}
}
const person = new Person("Alice Bob");
console.log(person.fullName); // Output: "Alice Bob"
person.fullName = ""; // Error: Name cannot be empty
person.fullName = "Charlie Brown";
console.log(person.fullName); // Output: "Charlie Brown"
Logger
object contains a log
method for timestamped logging.Person
and Employee
classes have their own functionalities.Object.assign
to mix the Logger
functionality into both classes by adding its methods to their prototypes.alice
(Person) and bob
(Employee) can use the log
method to log messages with timestamps.Decorators (still in the experimental stage) are functions that allow you to modify the behavior of classes, methods, or properties at runtime.
function logExecutionTime(target) {
const className = target.name; // Get the class name
const originalMethod = target; // Store the original method
target = function(...args) {
const startTime = performance.now();
const result = originalMethod.apply(this, args);
const endTime = performance.now();
console.log(`${className}.${originalMethod.name} execution time: ${(endTime - startTime).toFixed(2)} ms`);
return result;
};
return target;
}
@logExecutionTime // Decorator syntax (experimental)
class Math {
static add(x, y) {
return x + y;
}
}
console.log(Math.add(5, 3)); // Output: 0.01 ms (approximate execution time)
logExecutionTime
decorator is a function that takes a target (class, method, or property) as an argument.@logExecutionTime
syntax is used to decorate the Math.add
method (experimental syntax).Note: Decorators are still under development and might have syntax changes in future JavaScript versions.
#
) symbol.
class Person {
#name; // Private field (using # symbol)
constructor(name) {
this.#name = name; // Assign to the private field using #
}
getName() { // Public getter method
return this.#name;
}
setName(newName) { // Public setter method (optional for validation)
this.#name = newName;
}
}
const alice = new Person("Alice");
console.log(alice.getName()); // Output: "Alice" (using the getter)
// alice.#name is not accessible from outside the class!
#name
property is declared with a leading hash (#
) symbol, signifying it’s a private field.getName
) and setter (setName
) methods (optional) to control access and potentially validate data.Classes provide a powerful and organized way to create objects in JavaScript. They promote code reusability, maintainability, and better organization of your codebase. By understanding the core concepts, inheritance, advanced features like mixins and decorators (experimental), and private fields (ES2022+), you can leverage classes effectively in your JavaScript applications. Remember, this chapter provides a solid foundation, but you can always explore more advanced topics and best practices as you delve deeper into object-oriented programming in JavaScript. Happy coding !❤️