Methods and this

A class can also hold functions that work with the object's data. These functions are called methods. You write them inside the class body, without the function keyword:

class Employee {
  constructor(name, salary) {
    this.name = name;
    this.salary = salary;
  }

  giveRaise(amount) {
    this.salary += amount;
  }

  describe() {
    return `${this.name} earns ${this.salary}`;
  }
}

const a = new Employee("Alice", 3000);
const b = new Employee("Bob", 2800);
a.giveRaise(500);
console.log(a.describe());
console.log(b.describe());

Output:

Alice earns 3500
Bob earns 2800

Only Alice got the raise. When you call a.giveRaise(500), the object before the dot becomes this inside the method. So this.salary means Alice's salary. When you call b.describe(), this is Bob.

You have called methods before, like word.toUpperCase(). It works the same way. The value before the dot is the one the method works on.

Methods keep the rules in one place. The code that uses an employee just calls a.giveRaise(500). If you later want a maximum raise, you change only the giveRaise method, and every call follows the new rule. A method can also call another method of the same object with this, like this.describe().

There is one trap with this. It is set by how a method is called, not by where it is written. If you take a method out of its object and call it alone, this is undefined, and the program crashes:

class Pet {
  constructor(name) {
    this.name = name;
  }

  describe() {
    return `I am ${this.name}`;
  }
}

const cat = new Pet("Tom");
const f = cat.describe;
console.log(f());

Output:

/box/index.js:7
    return `I am ${this.name}`;
                        ^

TypeError: Cannot read properties of undefined (reading 'name')
    at describe (/box/index.js:7:25)
    at Object.<anonymous> (/box/index.js:13:13)

f() has no object before the dot, so this is undefined, and this.name fails. This often happens when you pass a method to another function, like map. The fix is to wrap the call in an arrow function. Then the method is still called with its object before the dot:

class Pet {
  constructor(name) {
    this.name = name;
  }

  describe() {
    return `I am ${this.name}`;
  }
}

const pets = [new Pet("Tom"), new Pet("Rex")];
console.log(pets.map(pet => pet.describe()));

Output:

[ 'I am Tom', 'I am Rex' ]

In the exercise, complete two methods: one that changes the salary, and one that returns a description.