Problem overview
A class bundles values with the questions you can ask about them. Rectangle remembers a width and a height and answers three questions: its area(), its perimeter() and whether it isSquare().
Each rectangle keeps its own sizes. A Rectangle(3, 4) has area 12, perimeter 14 and is not a square. A Rectangle(5, 5) has area 25, perimeter 20 and is a square. A Rectangle(2, 10) and a Rectangle(10, 2) both give 20 and 24: turning a rectangle on its side changes neither number.
Approach
The constructor stores the two parameters on the object, as this.width and this.height. Parameters disappear when the constructor ends, but properties on this stay with the object, so every other method can read them later. Each method then needs only those two numbers, so each one runs in O(1) time.
Step by step
- Store the sizes. In
constructor, assignwidthtothis.widthandheighttothis.height. - Area. Return
this.width * this.height. - Perimeter. Going around, you walk along each side once, so the length is twice the sum of the two sizes. Put the sum in parentheses so that it is computed before the multiplication by 2.
- Square. Return
this.width === this.height. A comparison is already a boolean, so noifis needed.
The solution in JavaScript
class Rectangle {
constructor(width, height) {
this.width = width;
this.height = height;
}
area() {
return this.width * this.height;
}
perimeter() {
return 2 * (this.width + this.height);
}
isSquare() {
return this.width === this.height;
}
}
Using the class
const a = new Rectangle(3, 4);
console.log(a.area(), a.perimeter(), a.isSquare());
const b = new Rectangle(5, 5);
console.log(b.area(), b.perimeter(), b.isSquare());
const c = new Rectangle(2, 10);
const d = new Rectangle(10, 2);
console.log(c.area(), c.perimeter(), c.isSquare());
console.log(d.area(), d.perimeter(), d.isSquare());
console.log(a.width, b.width);
This prints:
12 14 false
25 20 true
20 24 false
20 24 false
3 5
The last line shows that each object has its own width: a holds 3 and b holds 5. The lesson's tests print booleans as True and False; JavaScript itself writes true and false.
Common mistakes
- Forgetting
thisin the constructor. Writingwidth = width;only assigns the parameter to itself, and nothing is stored on the object. A method that readsthis.widththen getsundefined. - Forgetting
thisin a method. Writingreturn width * height;insidearea()looks for a variable calledwidth, and fails withReferenceError: width is not defined. Inside a method, the sizes are always reached throughthis. - Perimeter without parentheses.
2 * this.width + this.heightdoubles only the width. ForRectangle(3, 4)it gives 10 instead of 14. - Using
=instead of===inisSquare: a single=assigns, so the method would overwrite the height.
Testing
A few inputs worth trying, with what the class returns for them:
| Rectangle | area() | perimeter() | isSquare() |
|---|---|---|---|
| (1, 1) | 1 | 4 | true |
| (1, 10000) | 10000 | 20002 | false |
| (10000, 10000) | 100000000 | 40000 | true |
The largest sizes in the constraints give an area of 100000000. JavaScript numbers are doubles, which are exact for whole numbers up to 2 to the power 53, so there is no overflow to worry about.
The properties are ordinary and public, so code outside the class can read and change them. After const r = new Rectangle(3, 4); r.width = 6;, r.area() returns 24 and r.perimeter() returns 20: the methods always use the current values. Keeping the sizes inside the object is what makes the methods short: they take no parameters at all.
What new does
Writing new Rectangle(3, 4) creates an empty object, runs the constructor with this pointing at that object, and hands the object back. After const a = new Rectangle(3, 4), calling a.area() runs the method with this pointing at a, so this.width is 3. Calling b.area() runs the same code with this pointing at b. The class is written once; every object gets its own copy of the data.
