Introduction
In this article, I explain objects, prototypes, and classes, crucial elements that shape the anatomy of Object-Oriented Programming (OOP) in JavaScript.
Objects in JavaScript
Objects in JavaScript are fundamental entities that can store collections of key-value pairs. The keys are typically strings (or symbols), and the values can be any valid JavaScript data type, including numbers, strings, booleans, functions, arrays, and other objects. They are powerful data structures that can represent complex, real-world phenomena within our code.
Creating Objects
Creating objects in JavaScript can be done in a few ways. The most common method is using object literals. An object literal is defined within curly braces {}
.
let car = {
make: "Tesla",
model: "Model 3",
color: "red",
drive: function() {
console.log("The car is driving");
}
};
Another way is using the new Object()
constructor.
let car = new Object();
car.make = "Tesla";
car.model = "Model 3";
car.color = "red";
car.drive = function() {
console.log("The car is driving");
};
Object Properties and Methods
In JavaScript objects, the keys are known as properties and the values as their corresponding property values. If the property value is a function, we often refer to it as a method. Properties can be accessed and modified using the dot notation or bracket notation.
// Accessing properties
console.log(car.make); // Output: "Tesla"
console.log(car["color"]); // Output: "red"
// Modifying properties
car.make = "BMW";
car["color"] = "blue";
// Calling methods
car.drive(); // Output: "The car is driving"
Objects and References
In JavaScript, objects are reference types, meaning that when we assign an object to a new variable, we're not creating a new copy of the object, but rather creating a new reference to the same object.
let car1 = car;
car1.model = "Model S";
console.log(car.model); // Output: "Model S"
Even though we changed car1.model
, car.model
also changed because they both point to the same object.
Built-in Objects
JavaScript provides a rich set of built-in objects, such as Array, Date, and Math, that offer various functionalities. These objects have properties and methods that can be used to manipulate the data they hold or to perform complex operations.
let now = new Date();
console.log(now.getFullYear()); // Output: The current year
let numbers = [1, 2, 3];
console.log(numbers.length); // Output: 3
console.log(Math.sqrt(16)); // Output: 4
Prototypes in JavaScript
Every object in JavaScript has a hidden property called a prototype, which is another object that it "inherits" properties and methods from. This prototype object itself has a prototype of its own, forming a chain until we reach an object with a null prototype, which is the end of the prototype chain.
Prototype-based Inheritance
In JavaScript, inheritance is achieved through prototypes. When we try to access a property or a method on an object, JavaScript will first check the object itself. If it cannot find it there, it will look up the prototype chain until it finds the requested property or until it reaches the end of the chain.
Here's an example:
let vehicle = {
wheels: 4,
start: function() {
console.log("The engine is starting");
}
};
let car = Object.create(vehicle);
console.log(car.wheels); // Output: 4
car.start(); // Output: "The engine is starting"
In this case, car
doesn't have wheels
property or start
method of its own. But it can access these properties and methods through its prototype, vehicle
.
Prototype Chain
The prototype chain is a term that refers to the chain of objects linked through the prototype property. The chain starts from a specific object, moves up to its prototype, and continues up the prototypes until it reaches null
.
let vehicle = {
wheels: 4
};
let car = Object.create(vehicle);
car.make = "Tesla";
let myCar = Object.create(car);
myCar.owner = "John Doe";
console.log(myCar.wheels); // Output: 4
console.log(myCar.make); // Output: "Tesla"
console.log(myCar.owner); // Output: "John Doe"
In this case, myCar
object inherits properties from car
and vehicle
through the prototype chain.
Proto Property
The prototype of an object can be accessed via the __proto__
property. This property is not recommended for use in production code because it is not supported in all JavaScript environments and has been deprecated in favor of Object.getPrototypeOf()
.
console.log(car.__proto__ === vehicle); // Output: true
console.log(Object.getPrototypeOf(car) === vehicle); // Output: true
Built-in Prototypes
Built-in JavaScript constructors like Array, Object, Function, and others have prototypes that include methods and properties relevant to their instances. For example, Array.prototype
includes methods like push()
, pop()
, map()
, filter()
, and many others.
let arr = [1, 2, 3];
console.log(arr.__proto__ === Array.prototype); // Output: true
Classes in JavaScript
In JavaScript, classes are a type of function introduced in ES6 to offer a more traditional-looking way of defining constructor functions and prototype methods. They provide a clean and elegant syntax for creating objects and dealing with inheritance.
Creating Classes
To define a class, we use the class
keyword followed by the name of the class. Inside the class, we can define a constructor
function, which is a special method for creating and initializing objects created with that class.
class Car {
constructor(make, model) {
this.make = make;
this.model = model;
}
startEngine() {
console.log(`${this.make} ${this.model}'s engine is starting`);
}
}
let myCar = new Car("Tesla", "Model 3");
myCar.startEngine(); // Output: "Tesla Model 3's engine is starting"
Class Inheritance
Inheritance can be implemented in classes using the extends
keyword. A class created with extends
inherits all the methods from the parent class.
class ElectricCar extends Car {
constructor(make, model, batteryCapacity) {
super(make, model);
this.batteryCapacity = batteryCapacity;
}
chargeBattery() {
console.log(`${this.make} ${this.model}'s battery is charging`);
}
}
let myElectricCar = new ElectricCar("Tesla", "Model S", 100);
myElectricCar.startEngine(); // Output: "Tesla Model S's engine is starting"
myElectricCar.chargeBattery(); // Output: "Tesla Model S's battery is charging"
Private and Public Class Fields
By default, all properties and methods in a JavaScript class are public. However, ES2020 introduced a way to create private class fields using a hash #
prefix.
class Car {
#speed = 0;
accelerate() {
this.#speed += 10;
console.log(`Speed: ${this.#speed}`);
}
}
let myCar = new Car();
myCar.accelerate(); // Output: "Speed: 10"
console.log(myCar.#speed); // Throws an error: Property '#speed' is private and only accessible within class 'Car'.
Static Methods and Properties
Static methods and properties are those that belong to the class itself, not an instance of the class. You can declare a static method or property using the static
keyword.
class Car {
static numberOfWheels = 4;
static displayNumberOfWheels() {
console.log(`A car typically has ${this.numberOfWheels} wheels`);
}
}
Car.displayNumberOfWheels(); // Output: "A car typically has 4 wheels"