""
In JavaScript, constructor functions are a traditional way to create multiple objects with similar properties and methods. They provide a blueprint to produce many instances, each with their own unique data.
A constructor function is simply a regular function that is used with the new
keyword to create new objects. By convention, constructor function names start with a capital letter to distinguish them from normal functions.
this
Work Inside a Constructor?Inside a constructor function, this
refers to the new object being created. When you call a constructor with new
, JavaScript automatically:
this
to point to that new object.Here’s a simple example defining a Person
constructor:
function Person(name, age) {
this.name = name; // Assign name property to the new object
this.age = age; // Assign age property to the new object
this.greet = function() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};
}
Using the new
keyword, you can create as many Person
objects as you want, each with its own name and age:
const alice = new Person("Alice", 30);
const bob = new Person("Bob", 25);
alice.greet(); // Hello, my name is Alice and I am 30 years old.
bob.greet(); // Hello, my name is Bob and I am 25 years old.
Each instance has its own copy of the name
, age
, and the greet
method.
Car
ConstructorLet’s look at another example—a Car
constructor function:
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
this.getInfo = function() {
return `${this.year} ${this.make} ${this.model}`;
};
}
const car1 = new Car("Toyota", "Corolla", 2020);
const car2 = new Car("Tesla", "Model 3", 2023);
console.log(car1.getInfo()); // Output: 2020 Toyota Corolla
console.log(car2.getInfo()); // Output: 2023 Tesla Model 3
this
keyword inside a constructor refers to the new object being created.new
to instantiate objects from a constructor function.Constructor functions form the foundation of object creation in JavaScript and are essential to understand before moving on to more advanced OOP concepts like prototypes and ES6 classes.
JavaScript uses a prototype-based inheritance model, which is quite different from the classical inheritance found in many other programming languages. Understanding prototypes is key to writing efficient, reusable object-oriented code in JavaScript.
Every JavaScript object has an internal link to another object called its prototype. This prototype object can have properties and methods that the original object can access indirectly. This chain of links is called the prototype chain.
When you create multiple objects using a constructor function, you usually want to share common methods among them. If you define methods inside the constructor, each instance gets its own copy — which wastes memory.
Instead, JavaScript allows you to add shared methods to the constructor’s prototype. All instances then refer to the same method, saving memory and improving performance.
function Person(name, age) {
this.name = name;
this.age = age;
}
// Adding a method to the prototype, shared by all instances
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name}.`);
};
const alice = new Person("Alice", 30);
const bob = new Person("Bob", 25);
alice.greet(); // Hello, my name is Alice.
bob.greet(); // Hello, my name is Bob.
// Checking prototype relationship
console.log(alice.__proto__ === Person.prototype); // true
Here, greet
is defined only once on Person.prototype
, but both alice
and bob
can use it.
If you try to access a property or method on an object, JavaScript first looks at the object itself. If it doesn't find it there, it looks up the prototype chain until it finds it or reaches the end (null
).
console.log(alice.hasOwnProperty("name")); // true (own property)
console.log(alice.hasOwnProperty("greet")); // false (in prototype)
console.log(typeof alice.greet); // "function" (found via prototype)
You can create inheritance relationships between constructors by linking their prototypes.
Suppose we want a Student
to inherit from Person
:
function Student(name, age, grade) {
Person.call(this, name, age); // Call Person constructor with Student's context
this.grade = grade;
}
// Set Student's prototype to inherit from Person.prototype
Student.prototype = Object.create(Person.prototype);
// Fix constructor pointer because it points to Person now
Student.prototype.constructor = Student;
// Add a method specific to Student
Student.prototype.study = function() {
console.log(`${this.name} is studying.`);
};
const student1 = new Student("Charlie", 20, "A");
student1.greet(); // Inherited method: Hello, my name is Charlie.
student1.study(); // Student method: Charlie is studying.
In this example:
Student
calls Person
constructor to initialize shared properties.Student.prototype
is linked to Person.prototype
via Object.create()
.student1
inherits greet()
from Person
.Student
-specific methods like study()
are added to Student.prototype
..prototype
save memory by avoiding copies on each instance.Object.create()
to set up inheritance between constructor prototypes.Prototypes unlock the power of JavaScript inheritance, enabling code reuse and memory efficiency in your programs!
With ES6, JavaScript introduced the class syntax — a cleaner and more intuitive way to write constructor functions and work with inheritance. Although classes are mostly syntactic sugar over the existing prototype system, they make object-oriented programming easier to read and write.
A class declaration defines a blueprint for creating objects. Inside the class, the constructor
method sets up new instances.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
// Method shared by all instances
greet() {
console.log(`Hello, my name is ${this.name}.`);
}
}
const alice = new Person("Alice", 30);
alice.greet(); // Output: Hello, my name is Alice.
constructor
method runs automatically when you create a new instance with new
.greet
are added to the prototype behind the scenes.extends
and super
Classes can extend other classes to inherit properties and methods.
extends
keyword sets up the inheritance relationship.super()
function calls the parent class’s constructor.class Student extends Person {
constructor(name, age, grade) {
super(name, age); // Call Person's constructor
this.grade = grade;
}
// Override greet method
greet() {
console.log(`Hi, I am ${this.name}, and my grade is ${this.grade}.`);
}
study() {
console.log(`${this.name} is studying.`);
}
}
const student1 = new Student("Bob", 22, "A");
student1.greet(); // Hi, I am Bob, and my grade is A.
student1.study(); // Bob is studying.
Student
inherits name
and age
from Person
.greet
method is overridden to provide custom behavior.study
method is specific to Student
.Feature | Description | Example |
---|---|---|
Class Declaration | Defines blueprint with class keyword |
class Person { ... } |
Constructor | Initializes new instances | constructor(name, age) { ... } |
Methods | Defined inside class, shared via prototype | greet() { ... } |
Inheritance | Use extends to inherit a class |
class Student extends Person |
Super Call | Call parent constructor with super() |
super(name, age) |
Method Overriding | Redefine parent method in subclass | greet() { ... } |
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound.`);
}
}
class Dog extends Animal {
speak() {
console.log(`${this.name} barks.`);
}
}
const dog = new Dog("Rex");
dog.speak(); // Rex barks.
This simple example demonstrates how subclasses can extend and customize parent class behavior, all with a clean and concise syntax.
With ES6 classes, JavaScript’s object-oriented programming becomes more accessible and expressive — giving you a powerful tool for building structured and maintainable code!
Encapsulation is a fundamental concept in object-oriented programming that restricts direct access to some of an object's components, protecting the internal state and exposing only what’s necessary. In JavaScript, encapsulation can be achieved using closures and, more recently, private class fields.
Before private fields were introduced, one common way to create private variables and methods was through closures in constructor or factory functions. Variables defined inside the constructor or factory function are not accessible outside, but can be used by privileged methods.
function BankAccount(initialBalance) {
let balance = initialBalance; // Private variable
// Privileged method has access to private variable
this.deposit = function(amount) {
if (amount > 0) {
balance += amount;
console.log(`Deposited: $${amount}`);
}
};
this.getBalance = function() {
return balance;
};
}
const account = new BankAccount(100);
account.deposit(50);
console.log(account.getBalance()); // Output: 150
// Trying to access balance directly will fail
console.log(account.balance); // undefined
balance
is private because it’s scoped inside the constructor and inaccessible from outside.deposit
and getBalance
methods can access or modify balance
.Similarly, you can use factory functions to create objects with private data:
function createCounter() {
let count = 0; // private variable
return {
increment() {
count++;
},
getCount() {
return count;
}
};
}
const counter = createCounter();
counter.increment();
console.log(counter.getCount()); // 1
console.log(counter.count); // undefined
#fieldName
)Starting with ES2022, JavaScript introduced private class fields and methods using a #
prefix. These fields are truly private and cannot be accessed or modified from outside the class.
class User {
#password; // Private field
constructor(username, password) {
this.username = username;
this.#password = password;
}
checkPassword(input) {
return input === this.#password;
}
// Private method
#encryptPassword() {
// pretend encryption logic here
return btoa(this.#password);
}
showEncryptedPassword() {
return this.#encryptPassword();
}
}
const user = new User("alice", "secret123");
console.log(user.username); // alice
console.log(user.checkPassword("secret123")); // true
// Trying to access private field or method from outside causes error
console.log(user.#password); // SyntaxError
console.log(user.#encryptPassword()); // SyntaxError
#
before the name.Technique | How It Works | Accessibility |
---|---|---|
Closures | Variables scoped inside functions | Private to constructor/factory functions |
Private Class Fields (# ) |
Fields declared with # inside classes |
Truly private, inaccessible outside class |
Encapsulation in JavaScript protects your data and helps build robust, secure, and maintainable applications. Whether using closures or modern private fields, it’s an essential part of writing good object-oriented code.