JavaScript · Syntax · Beginner
OOP: Inheritance and Method Overriding
OOP problems in JavaScript on inheritance, super(), constructor, method overriding, toString(), custom class methods, and working with objects.
Quick topic start and explanations before exercises (exercises below):
toString() and custom methods
#Inheritance and method patterns
#Exercises:
Animal and Dog through inheritance.
#Create an Animal class, and the objects created from it must have a name property. The value for this property is passed when creating the object through the constructor. That is, the object describes an animal (any animal) and stores its name. Then create a Dog class that inherits from Animal. In the Dog class add a toString method that returns a string containing the type of animal (haha, sorry, "animal type" sounds funny) and its name: "Dog: Rex" # example of the returned string The idea is this: the base class Animal stores the main "behavior" of animal objects, while the class Dog adds details for a specific type of animal.
class Animal {
// your code here
}
class Dog extends Animal {
// your code here
}
Solution
class Animal {
constructor(name) {
this.name = name;
}
}
class Dog extends Animal {
toString() {
return `Dog: ${this.name}`;
}
}
Book with string representation.
#Create a Book class with title and pages object properties. Add a toString() method that returns: "Book: JavaScript Basics (120 pages)" You can also add a length() method that returns the number of pages in the book.
class Book {
// your code here
}
Solution
class Book {
constructor(title, pages) {
this.title = title;
this.pages = pages;
}
length() {
return this.pages;
}
toString() {
return `Book: ${this.title} (${this.pages} pages)`;
}
}
User and Admin.
#Let’s do something similar to the 1st one again: Task: Create a User class with a name property. Create an Admin class that inherits from User. Override the toString method so the output is: "Admin: Alex" And for a regular User the toString output should simply be: "Alex"
class User {
// your code here
}
class Admin extends User {
// your code here
}
Solution
class User {
constructor(name) {
this.name = name;
}
toString() {
return this.name;
}
}
class Admin extends User {
toString() {
return `Admin: ${this.name}`;
}
}
Box with items.
#Create a Box class with an items_count property. Add a length() method that returns the number of items. Also add add and remove methods that can put objects into and take objects out of the box. This can be done simply with the items_count counter (just count without extra complexity), or you can make an array of items in the box (strings) and adapt the class to work with the array (array as an object property).
class Box {
// your code here
}
Solution
class Box {
constructor(itemsCount) {
this.itemsCount = itemsCount;
}
add(count) {
if (count > 0) {
this.itemsCount += count;
}
}
remove(count) {
if (count > 0) {
this.itemsCount -= count;
if (this.itemsCount < 0) {
this.itemsCount = 0;
}
}
}
getCount() {
return this.itemsCount;
}
}
Message with spam flag.
#Create a Message class with text and spam properties. The text value is passed when creating the object through the constructor, and spam is initially equal to null. Add methods: isSpam() — checks whether the text contains words похожие на spam, returns true/false and stores the result in this.spam; length() — returns the length of the text.
class Message {
// your code here
}
Solution
class Message {
constructor(text) {
this.text = text;
this.spam = null;
this.spamTriggers = ["buy", "expensive"];
}
isSpam() {
if (this.spam !== null) {
return this.spam;
}
for (let trigger of this.spamTriggers) {
if (this.text.toLowerCase().includes(trigger)) {
this.spam = true;
return true;
}
}
this.spam = false;
return false;
}
length() {
return this.text.length;
}
}
let m = new Message("Buying old TVs for a high price!!!");
console.log(m.isSpam());
console.log(m.length());
Employee and Manager.
#Create an Employee class with name and salary properties. Make a method in Employee that can change the salary. Create a Manager class that inherits from Employee. Override the toString method so that the output is: Manager John earns 5000 Make sure the salary changing method also works for Manager
class Employee {
// your code here
}
class Manager extends Employee {
// your code here
}
Solution
class Employee {
constructor(name, salary) {
this.name = name;
this.salary = salary;
}
changeSalary(coef) {
this.salary = Math.round(this.salary * coef);
}
}
class Manager extends Employee {
toString() {
return `Manager ${this.name} earns ${this.salary}`;
}
}
let manager = new Manager("Bob", 1000);
manager.changeSalary(1.1);
console.log(manager.toString());
Playlist and CustomPlaylist.
#Create a Playlist class with a songs property (array). Add add and remove methods for adding and removing songs. Add a reverse() method that reverses the track array. Add a length() method that returns the number of songs. Add an isEmpty() method that checks whether the playlist is empty or not. Then create a child class CustomPlaylist, where the add() method allows duplicate songs to be added to the playlist. In the base Playlist duplicates must not be allowed.
class Playlist {
// your code here
}
Solution
class Playlist {
constructor(songs) {
this.songs = songs;
}
add(song) {
if (!this.songs.includes(song)) {
this.songs.push(song);
}
}
remove(song) {
if (this.songs.includes(song)) {
this.songs.splice(this.songs.indexOf(song), 1);
}
}
reverse() {
this.songs.reverse();
}
length() {
return this.songs.length;
}
isEmpty() {
return this.songs.length === 0;
}
}
class CustomPlaylist extends Playlist {
add(song) {
this.songs.push(song);
}
}
Named CustomPlaylist.
#Improve the previous CustomPlaylist class by adding its own constructor. It must call the parent class constructor through super(songs), and then save the playlist name into the name property.
class CustomPlaylist extends Playlist {
constructor(songs, name) {
super(songs);
// your code here
}
add(song) {
this.songs.push(song);
}
}
Solution
class Playlist {
constructor(songs) {
this.songs = songs;
}
add(song) {
if (!this.songs.includes(song)) {
this.songs.push(song);
}
}
}
class CustomPlaylist extends Playlist {
constructor(songs, name) {
super(songs);
this.name = name;
}
add(song) {
this.songs.push(song);
}
toString() {
return `Playlist: ${this.name}`;
}
}
MagicBox with a random item.
#Let’s return to the Box class (the code is below). Let’s inherit from it and create a MagicBox class. The only added behavior is that when a box object is created, a random item from an array will appear inside it. Define the array of possible random items wherever you want, it does not matter, even in the global scope. Template:
class Box {
constructor() {
this.items = [];
this.itemsCount = this.items.length;
}
add(item) {
this.items.push(item);
this.itemsCount = this.items.length;
}
remove(item) {
if (this.items.includes ? this.items.includes(item) : (item in this.items)) {
this.items.splice(this.items.indexOf(item), 1);
this.itemsCount = this.items.length;
} else {
console.log("The cat from the box says: That's not here, goodbye!");
}
}
length() {
return this.itemsCount;
}
}
let things = ["Hat", "Umbrella", "Mug"];
class MagicBox extends Box {
constructor() {
// call super() and add a random item
}
}
Solution
function choice(items) {
return items[Math.floor(Math.random() * items.length)];
}
class Box {
constructor() {
this.items = [];
this.itemsCount = this.items.length;
}
add(item) {
this.items.push(item);
this.itemsCount = this.items.length;
}
remove(item) {
if (this.items.includes(item)) {
this.items.splice(this.items.indexOf(item), 1);
this.itemsCount = this.items.length;
} else {
console.log("The cat from the box says: That's not here, goodbye!");
}
}
length() {
return this.itemsCount;
}
}
const things = ["Hat", "Umbrella", "Mug"];
class MagicBox extends Box {
constructor() {
super();
this.items.push(choice(things));
this.itemsCount = this.items.length;
}
}