Mark As Completed Discussion

Accessing the Object Itself

All OOP-supported programming languages have a special keyword or way to access the "self" object from within a class. For Java and C++, it is this. For Python, it can be named anything but is by convention self.

Suppose you are creating a constructor for the Rectangle class which will take the parameters height and width. You can define the constructor like below:

1class Rectangle extends Shape {
2    constructor(h, w) {
3        super();
4        this.height = h;
5        this.width = w;
6    }
7}

But what if you wanted to name the parameters the same thing as the attributes of the class? It would be easier for the user of the class to understand the method signature Rectangle(int height, int width) instead of Rectangle(int h, int w). However, after renaming the parameters, if we use the identifier height or width inside the function, then it will always refer to the parameter (closest scope) and not the attributes. So how do we refer to attributes with the same name?

Here we can use the this keyword to refer to anything of "this" class and not anything outside of the class. See the code below:

1class Rectangle extends Shape {
2    constructor(height, width) {
3        super();
4        // this.height => height attribute of Rectangle.
5        // height => height parameter of the constructor method.
6        this.height = height;
7        this.width = width;
8    }
9}

In addition to referencing attributes with the same name as parameters, you also have to access the object itself in order to pass an object to an outside function from within the class. For example, suppose you have a class named GetOne whose job is to return one Rectangle object from two Rectangle objects. Additionally, suppose you have a method in Rectangle that takes a GetOne class and a Rectangle object then updates itself to become a copy of the returned object. Let us first define the GetOne class hierarchy.

1class GetOne {
2    get(rect1, rect2) {
3        // Just return the first one for now.
4        return rect1;
5    }
6}
7
8class GetSmallerArea extends GetOne {
9    get(rect1, rect2) {
10        return rect1.getArea() <= rect2.getArea() ? rect1 : rect2;
11    }
12}
13
14class GetLargerArea extends GetOne {
15    get(rect1, rect2) {
16        return rect1.getArea() < rect2.getArea() ? rect2 : rect1;
17    }
18}

Note: In Go, there's no concept of class inheritance like in Java. Instead, Go uses composition and embedding. The given Go code assumes a struct named Rectangle exists with a method getArea.

Now we define the method inside the Rectangle class. The method will take GetOne and another Rectangle object then update itself using get methods. For this, we need to pass two objects to the get method. One object will be the Rectangle and the other will be itself. See below how we can do that:

1class Rectangle extends Shape {
2    constructor(height, width) {
3        super();
4        this.height = height;
5        this.width = width;
6    }
7
8    compareAndUpdate(comparator, other) {
9        // Passing myself to comparator with "this" keyword
10        let one = comparator.get(this, other);
11        this.height = one.height;
12        this.width = one.width;
13    }
14
15    toString() {
16        return `Rectangle(${this.height},${this.width})`;
17    }
18}

In the main method, we can use this like below:

1// Assuming necessary class definitions from previous conversions
2const main = () => {
3    // Using concept of polymorphism
4    let smaller = new GetSmallerArea();
5    let larger = new GetLargerArea();
6
7    let rect1 = new Rectangle(3, 4);
8    let rect2 = new Rectangle(5, 6);
9
10    rect1.compareAndUpdate(smaller, rect2);
11    console.log(rect1.toString()); // Rectangle(3,4)
12
13    rect1.compareAndUpdate(larger, rect2);
14    console.log(rect1.toString()); // Rectangle(5,6)
15}
16
17main();