JavaScript Classes
Variables can be used to hold information about the state your code is in, e.g. how many times someone has clicked on a button:
let timesClicked = 0;
let whenButtonClicked = () => {
timesClicked++;
console.log(`Button has been clicked ${timesClicked} times`);
};
document
.querySelector("#myButton")
.addEventListener("click", whenButtonClicked);
However, you may end up being in a situation where you'll have to keep track of the click state of multiple buttons, or even a dynamic number of buttons:
let timesClicked1 = 0;
let timesClicked2 = 0;
let whenButtonClicked1 = () => {
timesClicked1++;
console.log(`Button has been clicked ${timesClicked1} times`);
};
let whenButtonClicked2 = () => {
timesClicked2++;
console.log(`Button has been clicked ${timesClicked2} times`);
};
document
.querySelector("#myButton1")
.addEventListener("click", whenButtonClicked1);
document
.querySelector("#myButton2")
.addEventListener("click", whenButtonClicked2);
We can reduce this code duplication by using a JavaScript class
(not the same as a class in CSS). Classes are templates which are used to create objects containing methods and properties of the class. For example here the class Counter
ties together the state, timesClicked
, and the functions that reference it like whenButtonClicked
:
class Counter {
constructor() {
this.timesClicked = 0;
}
whenClicked() {
this.timesClicked++;
console.log(`Button has been clicked ${this.timesClicked} times`);
}
}
let counter1 = new Counter();
let counter2 = new Counter();
document
.querySelector("#myButton1")
.addEventListener("click", () => counter1.whenClicked());
document
.querySelector("#myButton2")
.addEventListener("click", () => counter2.whenClicked());
We can create instances of a class using the new
operator, followed by the class name. When a class instance is created, its constructor
function is called automatically. We can pass the constructor arguments to use during initialisation.
For example, here is a CounterFromN
class that starts counting from a number that's passed in:
class CounterFromN {
constructor(n) {
this.timesClicked = n;
}
whenClicked() {
this.timesClicked++;
console.log(`Button has been clicked ${this.timesClicked} times`);
}
}
let counterFromTen = new CounterFromN(10);
counterFromTen.whenClicked();
// Button has been clicked 11 times
As shown above, a class' functions can be called by referring to the name of the object's function followed by brackets. If the function expects any arguments then these can be passed into it inside the brackets as per normal. Functions defined within classes are also be known as methods.
Variables specific to a particular instance of a class are defined and referenced using the this
keyword (e.g. this.timesClicked
) within that instance. this
refers to the object which is created by the class when it instantiated.
Exercises
Try these exercises in your breakout groups.
Exercise 1
Implement the add
and getTotal
methods of the RunningTotal
class below.
class RunningTotal {
constructor() {
this.currentTotal = 0;
}
add(n) {
// Implement this method
}
getTotal() {
// Implement this method
}
}
const runningTotal = new RunningTotal();
runningTotal.add(3);
runningTotal.add(7);
runningTotal.add(7);
runningTotal.getTotal();
// 17
Exercise 2
Implement the constructor
method of the StopWatch
class below.
class StopWatch {
constructor() {
this.secondsElapsed = 0;
//Finish implementing the rest of the constructor so that secondsElapsed is updated
}
getTime() {
return `Seconds elapsed: ${this.secondsElapsed}`;
}
}
const stopWatch = new StopWatch();
// Wait a few seconds...
stopWatch.getTime();
// 'Seconds elapsed: 3'
// Wait a few more seconds...
stopWatch.getTime();
// 'Seconds elapsed: 7'
Exercise 3
Implement the constructor
, store
and the lookup
methods of the AddressBook
class below.
class AddressBook {
// Implement the constructor method
// Implement the store method
// Implement the lookup method
}
const myAddresBook = new AddressBook();
myAddressBook.store("bart", "bart@simpsons.com");
myAddressBook.store("maggie", "maggie@simpsons.com");
myAddressBook.lookup("bart");
// 'bart@simpsons.com'
myAddressBook.lookup("homer");
// 'address not found'
Notice that when you come to using a class instance, you are only interacting with it through its methods, e.g. store
and lookup
for AddressBook
. Similar to functions, classes provide a way of creating abstractions over lower-level implementations, which can help us better organise and maintain our code.