10 OOP in JavaScript Interview Questions and Answers
Prepare for your next interview with this guide on OOP in JavaScript, featuring common questions and answers to enhance your coding skills.
Prepare for your next interview with this guide on OOP in JavaScript, featuring common questions and answers to enhance your coding skills.
Object-Oriented Programming (OOP) in JavaScript is a fundamental concept that underpins many modern web development practices. By leveraging OOP principles, developers can create more modular, reusable, and maintainable code. JavaScript’s flexibility allows for the implementation of OOP concepts such as inheritance, encapsulation, and polymorphism, making it a powerful tool for building complex applications.
This article provides a curated selection of interview questions focused on OOP in JavaScript. Reviewing these questions will help you deepen your understanding of OOP principles and demonstrate your proficiency in applying them within JavaScript, thereby enhancing your readiness for technical interviews.
Car
with properties for make, model, and year. Include a method to display this information.In JavaScript, a class can be defined using the class
keyword. The class can have a constructor to initialize its properties and methods to perform actions. Here is an example of a Car
class with properties for make, model, and year, and a method to display this information:
class Car { constructor(make, model, year) { this.make = make; this.model = model; this.year = year; } displayInfo() { return `${this.year} ${this.make} ${this.model}`; } } const myCar = new Car('Toyota', 'Corolla', 2020); console.log(myCar.displayInfo()); // Output: 2020 Toyota Corolla
Inheritance allows a class to inherit properties and methods from another class. This is achieved using the extends
keyword. The child class can also override or extend the functionality of the parent class.
Example:
class Animal { constructor(name) { this.name = name; } speak() { console.log(`${this.name} makes a noise.`); } } class Dog extends Animal { constructor(name, breed) { super(name); this.breed = breed; } speak() { console.log(`${this.name} barks.`); } } const dog = new Dog('Rex', 'German Shepherd'); dog.speak(); // Rex barks.
In this example, the Dog
class inherits from the Animal
class. The Dog
class uses the super
keyword to call the constructor of the Animal
class, ensuring that the name
property is properly initialized. The speak
method in the Dog
class overrides the speak
method in the Animal
class.
Polymorphism allows methods to do different things based on the object it is acting upon. This is typically achieved through method overriding, where a subclass provides a specific implementation of a method that is already defined in its superclass.
Example:
class Animal { speak() { console.log("The animal makes a sound"); } } class Dog extends Animal { speak() { console.log("The dog barks"); } } class Cat extends Animal { speak() { console.log("The cat meows"); } } function makeAnimalSpeak(animal) { animal.speak(); } const myDog = new Dog(); const myCat = new Cat(); makeAnimalSpeak(myDog); // The dog barks makeAnimalSpeak(myCat); // The cat meows
Encapsulation is the practice of bundling data and methods that operate on the data into a single unit, typically a class. It also involves restricting access to some of the object’s components, which can be done using private fields and methods. This ensures that the internal representation of the object is hidden from the outside, only exposing a controlled interface.
Example using ES6 classes and private fields:
class Person { #name; // private field constructor(name) { this.#name = name; } getName() { return this.#name; } setName(newName) { if (typeof newName === 'string' && newName.length > 0) { this.#name = newName; } else { console.log('Invalid name'); } } } const person = new Person('John'); console.log(person.getName()); // John person.setName('Doe'); console.log(person.getName()); // Doe console.log(person.#name); // SyntaxError: Private field '#name' must be declared in an enclosing class
In this example, the #name
field is private and cannot be accessed directly from outside the class. The getName
and setName
methods provide controlled access to the private field.
Animal
and extend it to create a subclass Dog
. Add a method to each class and demonstrate calling these methods.In JavaScript, classes are a template for creating objects. The extends
keyword is used to create a subclass, which inherits methods and properties from a parent class.
class Animal { constructor(name) { this.name = name; } speak() { console.log(`${this.name} makes a noise.`); } } class Dog extends Animal { constructor(name, breed) { super(name); this.breed = breed; } speak() { console.log(`${this.name} barks.`); } } const animal = new Animal('Generic Animal'); animal.speak(); // Generic Animal makes a noise. const dog = new Dog('Rex', 'German Shepherd'); dog.speak(); // Rex barks.
Getters and setters are used to control access to an object’s properties. A getter method allows you to define a method that will be executed when a property is accessed, while a setter method allows you to define a method that will be executed when a property is set. This provides a way to add logic to the process of getting or setting a property value.
Here is an example of a JavaScript class that uses both getters and setters:
class Person { constructor(name, age) { this._name = name; this._age = age; } // Getter for name get name() { return this._name; } // Setter for name set name(newName) { if (typeof newName === 'string' && newName.length > 0) { this._name = newName; } else { console.error('Invalid name'); } } // Getter for age get age() { return this._age; } // Setter for age set age(newAge) { if (typeof newAge === 'number' && newAge > 0) { this._age = newAge; } else { console.error('Invalid age'); } } } const person = new Person('John', 30); console.log(person.name); // John person.name = 'Doe'; console.log(person.name); // Doe person.age = 25; console.log(person.age); // 25
super
keyword. Provide an example.The super
keyword allows a child class to call and access properties and methods of its parent class. When a child class extends a parent class, the super
keyword can be used to call the parent’s constructor and methods, ensuring that the parent class is properly initialized and its functionality is available to the child class.
Example:
class Animal { constructor(name) { this.name = name; } speak() { console.log(`${this.name} makes a noise.`); } } class Dog extends Animal { constructor(name, breed) { super(name); this.breed = breed; } speak() { super.speak(); console.log(`${this.name} barks.`); } } const dog = new Dog('Rex', 'German Shepherd'); dog.speak();
In this example, the Dog
class extends the Animal
class. The super
keyword is used in the Dog
constructor to call the Animal
constructor, ensuring that the name
property is properly initialized. Additionally, the super.speak()
call in the Dog
class’s speak
method allows the Dog
class to reuse the speak
method from the Animal
class before adding its own behavior.
Method overriding occurs when a subclass provides a specific implementation of a method that is already defined in its superclass. This allows the subclass to modify or extend the behavior of the inherited method. It is a key feature for achieving polymorphism in object-oriented programming.
Example:
class Animal { speak() { console.log("The animal makes a sound"); } } class Dog extends Animal { speak() { console.log("The dog barks"); } } let myDog = new Dog(); myDog.speak(); // Output: The dog barks
In this example, the Dog
class overrides the speak
method of the Animal
class. When the speak
method is called on an instance of Dog
, the overridden method in the Dog
class is executed, demonstrating how method overriding allows for specific behavior in subclasses.
Static methods and properties are defined using the static
keyword. They are called on the class itself, not on instances of the class. This means you can use them without creating an instance of the class. Static methods are typically used for utility functions, such as functions that perform operations on data that is passed to them as arguments.
Example:
class MathUtils { static add(a, b) { return a + b; } static get description() { return 'This class provides basic math utilities.'; } } console.log(MathUtils.add(5, 3)); // 8 console.log(MathUtils.description); // This class provides basic math utilities.
In this example, add is a static method and description is a static property. They can be accessed directly on the MathUtils
class without creating an instance of the class.
Object composition is a design principle where objects are composed using other objects, rather than inheriting from a parent class. This approach allows for greater flexibility and reusability, as it avoids the pitfalls of a rigid class hierarchy.
Example of inheritance:
class Animal { constructor(name) { this.name = name; } speak() { console.log(`${this.name} makes a noise.`); } } class Dog extends Animal { speak() { console.log(`${this.name} barks.`); } } const dog = new Dog('Rex'); dog.speak(); // Rex barks.
Example of object composition:
const canSpeak = (state) => ({ speak: () => console.log(`${state.name} makes a noise.`) }); const canBark = (state) => ({ bark: () => console.log(`${state.name} barks.`) }); const createDog = (name) => { const state = { name }; return Object.assign({}, canSpeak(state), canBark(state)); }; const dog = createDog('Rex'); dog.speak(); // Rex makes a noise. dog.bark(); // Rex barks.