Repository navigation
- intro
- Static Methods
- Getter and Setters
An alternative way to structure our code, Object Orientation. By understanding and using OO, we can design our code to be easier to read, understand and change.
Object Orientation grants us the ability to write code that structurally establishes the relationships between data and functions.
- Easier to Change
- Offers Better Data Control
- Easy to Replicate
- Improves Understanding by Adding Meaning
The class keyword is just syntactic sugar, or a nice abstraction, over JavaScript's existing prototypal object structure. no
functionkeyword is used for instance methods.
class Square {
constructor(sideLength) {
this.sideLength = sideLength;
}
// notice how the instance method doesn't have the `function` keyword
area() {
return this.sideLength * this.sideLength;
}
}
let square = new Square(5);
square; // => Square { sideLength: 5 }
square.sideLength; // => 5
square.area(); // => 25In class methods, this acts similar to Ruby's self keyword. this can be used to refer to properties of an instance, like name and age, or methods of an instance (this.sayName()).
You can also access the properties of an instance with:
square[`sideLenght`]
// => 5
square[`sideLenght`] = 13So to use variables to call properties.
Static methods are class level methods - they are not callable on instances of a class, only the class itself. These are often used in 'utility' class that encapsulate a set of methods but don't need to be made into instances. For example, we could write a CommonMath class that stores a series of math related methods.
For static methods, this references the class. This means that you can call a static method from within another static method of the same class using this.
class CommonMath {
static triple(number) {
return number * number * number;
}
static findHypotenuse(a, b) {
return Math.sqrt(a * a + b * b);
}
static doubleTriple(number) {
return this.triple(number) * 2
}
}
let num = CommonMath.triple(3);
num; // => 27
let c = CommonMath.findHypotenuse(3, 4);
c; // => 5This sort of class might be useful in many different situations, but we don't ever need an instance of it.
In modern JavaScript get has been introduced for methods which serve the specific purpose of retrieving data from an instance.
class Square {
constructor(sideLength) {
this.sideLength = sideLength;
}
get area() {
return this.sideLength * this.sideLength;
}
}
let square = new Square(5);
square.sideLength; // => 5
square.area; // => 25If you try to use this.area(), you'll receive a TypeError. area is no longer considered a function!
//BAD PRACTICE!
class Square {
constructor(sideLength) {
this.sideLength = sideLength;
this.area = sideLength * sideLength;
}
}This is valid code, but what we've done is load our constructor with more calculations.
The main benefit to using get is that your area calculation isn't actually run until it is accessed.
If included in the constructor, an expensive process will be called every time a new instance of a class is created.
Since properties can change, any values dependent on them should be calculated based on the current property values, otherwise we will run in to issues like this:
//also:
class Square {
constructor(sideLength) {
this.sideLength = sideLength;
this.area = sideLength * sideLength;
}
}
let square = new Square(5);
square.area; // => 25
square.sideLength = 10;
square.area; // => 25class Square {
constructor(sideLength) {
this.sideLength = sideLength;
}
get area() {
return this.sideLength * this.sideLength;
}
}
square.sideLength = 10;
square.area; // => 100We can change area by changing sideLenght however we can't assign area a new value. To make area fully act like a real property, we create both get and set methods for it:
class Square {
constructor(sideLength) {
this.sideLength = sideLength;
}
get area() {
return this.sideLength * this.sideLength;
}
set area(newArea) {
this.sideLength = Math.sqrt(newArea);
}
}
let square = new Square(5);
square.sideLength; // => 5
square.area; // => 25
square.area = 64;
square.sideLength; // => 8
square.area; // => 64area became a pseudo-property.
From the outside, it looks like a property is being set, but behind the scenes, we can define what we want to happen, including applying conditional statements:
set area(newArea) {
if (newArea > 0) {
this.sideLength = Math.sqrt(newArea)
} else {
console.warn("Area cannot be less than 0");
}
}All properties are accessible from outside an instance, as we see with square.sideLength, as well as from within class methods (this.sideLength).
class Transaction {
constructor(amount, date, memo) {
this.amount = amount;
this.date = date;
this.memo = memo;
}
}The date, amount and memo properties represent fixed values for each instance when a Transaction instance is created and probably shouldn't be altered. However, it is still possible to change these properties.
there is no official way to make a property private - all class and object properties are exposed as we see above. One common convention, however, is to include an underscore at the beginning of the property name to indicate those properties are not intended to be accessed from outside the class:
class Transaction {
constructor(amount, date, memo) {
this._amount = amount;
this._date = date;
this._memo = memo;
}
}Implementing private properties is planned in future versions of JavaScript, and will use a # symbol to indicate a property is private.
You may remember, though that in JavaScript, properties are exposed. That is, any property can be reassigned from outside. Here is where get and set really shine. With get and set, we can define the 'public' facing methods for updating a 'private' property.
In this Student class, we've set up a pseudo-property, firstName, which refers to a 'private' property _firstName:
class Student {
constructor(firstName, lastName) {
this._firstName = this.sanitize(firstName);
this._lastName = this.sanitize(lastName);
}
get firstName() {
return this.capitalize(this._firstName);
}
set firstName(firstName) {
this._firstName = this.sanitize(firstName);
}
capitalize(string) {
// capitalizes first letter
return string.charAt(0).toUpperCase() + string.slice(1);
}
sanitize(string) {
// removes any non alpha-numeric characters except dash and single quotes (apostrophes)
return string.replace(/[^A-Za-z0-9-']+/g, '');
}
}
let student = new Student('Carr@ol-Ann', ')Freel*ing');
student; // => Student { _firstName: 'Carrol-Ann', _lastName: 'Freeling' }
student.firstName = 'Hea@)@(!$)ther';
student.firstName; // => 'Heather'normal instance methods can do everything that get and set can do.
All class methods and properties are exposed for use 'publicly'. Using get and set is purely for design purposes to produce better organized, easier to understand classes.
We can use get and set whenever we are handling input or output of a class. We are, in essence, creating the public interface of the class.
get and set methods are the ways in which other classes and code should utilize this class.
Using this design, all remaining methods can be considered private. They don't deal with input and output; they are only used internally as helper methods.
Using a setter, you can call a function each time the value of a pseudo-property is changed, making sure all data on a class instance is consistent. Using a getter, you can return a computed value as though it is a property!