Understanding Prototype Chains and Classes in JavaScript
Written on
Chapter 1: Introduction to JavaScript's Object-Oriented Programming
In this article, we will explore the foundational elements of Object-Oriented Programming (OOP) in JavaScript, presented in four distinct steps.
- Single Objects: How do standalone objects function, which are the fundamental building blocks of OOP in JavaScript?
- Prototype Chains: Every object can possess zero or more prototype chains. Prototypes serve as JavaScript's core inheritance mechanism.
- Classes: Classes act as factories for objects in JavaScript. The relationship between a class and its instances is based on prototypical inheritance.
- Subclassing: The relationship between a subclass and its superclass is also rooted in prototypical inheritance.
As we delve deeper, we will uncover how prototypes are the sole inheritance mechanism in JavaScript, allowing each object to have either a null prototype or one that is another object. In the latter case, the object inherits all properties from its prototype.
Consider the following example:
const proto = {
protoProp: "a"
}
const obj = {
__proto__: proto,
objProp: "b"
}
// obj inherits the protoProp property:
console.log(obj.protoProp) // "a"
console.log("protoProp" in obj) // true
In this case, obj has its own property, objProp, alongside the inherited protoProp.
Chapter 2: The Mechanics of Prototype Chains
The first video, "JavaScript Karmaşası : 04 : Object Part II, Prototype nedir?, Inheritance, Basic Object, __proto__ - YouTube", elaborates on key concepts surrounding prototypes and inheritance in JavaScript.
Continuing with our exploration, we find that a prototype object can also serve as a prototype for other objects, resulting in a chain of objects known as the prototype chain. This mechanism creates the illusion that we are dealing with single objects, while in reality, we are managing chains of objects.
In further detail, the following code illustrates how the property protoProp can be overridden by the obj instance:
const proto = {
protoProp: "a"
}
const obj = {
__proto__: proto,
objProp: "b"
}
obj.protoProp = "x"; // This creates a new property on obj
console.log(Object.keys(obj)); // ["objProp", "protoProp"]
console.log(proto.protoProp); // "a"
console.log(obj.protoProp); // "x"
This demonstrates that the prototype's properties remain unchanged, while the object's own properties can overshadow inherited ones.
The second video, "51-Javascript Dersleri - Javascript Prototype - YouTube", provides additional insights into the workings of prototypes in JavaScript.
Chapter 3: Advanced Prototype Handling
To work effectively with prototypes, it is advisable to avoid the __proto__ pseudo-property whenever possible. Instead, one should use Object.getPrototypeOf(obj) to retrieve a prototype and Object.create(proto) to establish a prototype.
For example:
const proto1 = { name: "proto1" }
const obj = Object.create(proto1);
console.log(Object.getPrototypeOf(obj)); // { name: "proto1" }
To alter an existing object's prototype, you can use Object.setPrototypeOf(obj, newProto), although this may have performance implications.
In the realm of data sharing via prototypes, we note that similar objects can share methods to avoid redundancy. Consider the following approach:
const PersonProto = {
describe() {
return "Person named " + this.name;}
}
const jane = {
__proto__: PersonProto,
name: "Jane"
}
const tarzan = {
__proto__: PersonProto,
name: "Tarzan"
}
Both jane and tarzan leverage the describe method from PersonProto, showcasing the power of prototypes in JavaScript.
Chapter 4: Transitioning to Classes
With a solid understanding of prototype chains, we can now introduce classes, which provide a more concise syntax for establishing these relationships.
A class for persons can be defined as follows:
class Person {
constructor(name) {
this.name = name;}
describe() {
return "Person named " + this.name;}
}
Using the new Person() constructor, we can create instances such as jane and tarzan easily:
const jane = new Person("Jane");
console.log(jane.describe()); // "Person named Jane"
In this chapter, we will dive into class expressions, static methods, and the intricacies of class design and inheritance, enhancing your JavaScript skills significantly.
As we wrap up our exploration of prototypes and classes, remember that while these concepts may seem complex, they form the backbone of JavaScript's OOP capabilities, enabling you to write more efficient and organized code.
For further learning, don't forget to subscribe and show your support by clicking the applause button below! 👏
Want to Connect?
Twitter — GitHub