Setters don't run on a initializing an instance of a class

Hi,

I am on the classes part of the course and I really don’t understand something about setters.

class School {
  constructor(name, level, numberOfStudents) {
    this._name = name;
    this._level = level;
    this._numberOfStudents = numberOfStudents;
  }
  set numberOfStudents(number) {
    if (typeof number === "Number") {
      this._numberOfStudents = number;
    } else {
      console.log('Invalid input: numberOfStudents must be set to a Number.');
    }
}
class High extends School {
  constructor(name, numberOfStudents, sportsTeam) {
    super(name, 'high', numberOfStudents);
    this._sportsTeam = sportsTeam;
  }
  get sportsTeam() {
    return this._sportsTeam;
  }
}

These are the getters and setters and below is creating an instance.

//create an instance of the class
const alSmith = new High('Al E. Smith', 500, ['Baseball', 'Basketball', 'Volleyball', 'Track and Field'])
// try to change the number of students
alSmith.numberOfStudents = 415; // sets numberOfStudents to 415
//try to set as an incorrect value
alSmith.numberOfStudents = 'apple'; //logs 'Invalid input: numberOfStudents must be set to a Number.' as expected.

This is all fine but I don’t really see how it’s that useful because we set the values upon initializing the instance.

const alSmith = new High('Al E. Smith', 500, ['Baseball', 'Basketball', 'Volleyball', 'Track and Field'])
console.log(alSmith.numberOfStudents); // returns 500
const alSmith = new High('Al E. Smith', 'apple', ['Baseball', 'Basketball', 'Volleyball', 'Track and Field'])
console.log(alSmith.numberOfStudents); // returns 'apple'

Obviously when we initialise the instance we want to make sure that out data is clean, I thought that this is why we used setters. But when I make the new instance I can set whatever value i like as numberOfStudents and it won’t throw an error message. Can someone tell me why this is? And how you would use a setter when you initialise an instance?

Hey @microrockstar97864
I would say the setters are there so you can change the value of property after the object has been initialized. Yes, in this case there is no type checking in the constructor but you could build that in as below.

class School { constructor(name, level, numberOfStudents) { this._name = name; this._level = level; if (typeof numberOfStudents === "number") { this._numberOfStudents = numberOfStudents; } else { console.log('Invalid input in constructor: numberOfStudents must be set to a Number. Type is actually: ' + typeof numberOfStudents); } this._numberOfStudents = numberOfStudents; } set numberOfStudents(number) { console.log('Attempting to set to: ' + number); if (typeof number === "number") { this._numberOfStudents = number; } else { console.log('Invalid input: numberOfStudents must be set to a Number. Type is actually: ' + typeof number); } } } class High extends School { constructor(name, numberOfStudents, sportsTeam) { super(name, 'high', numberOfStudents); this._sportsTeam = sportsTeam; } get sportsTeam() { return this._sportsTeam; } } //create an instance of the class const alSmith = new High('Al E. Smith', 'string data', ['Baseball', 'Basketball', 'Volleyball', 'Track and Field']); // try to change the number of students alSmith.numberOfStudents = 415; // sets numberOfStudents to 415 //try to set as an incorrect value alSmith.numberOfStudents = 'apple'; //logs 'Invalid input: numberOfStudents must be set to a Number.' as expected.

I see what you mean so we build the if statment right into the constructor. It makes sense, thanks for that. I guess I just didn’t fully understand the role of a setter! Would you use this as well as a setter?

Number (not a string) is the name of the class (as in constructor) and 'number' (a string) is the typeof, as in the name of the type.

number = 42
console.log(typeof number)    //  'number'

You could call the setter from the constructor. I did it in the Codebyte below. That way you aren’t duplicating the if statement in the setter.

class School { constructor(name, level, numStudents) { this._name = name; this._level = level; this._numberOfStudents = 0; // set it to 0 first just to initialize the variable; this.numberOfStudents = numStudents; // call the setter } set numberOfStudents(number) { console.log('Attempting to set to: ' + number); // for logging purposes if (typeof number === 'number') this._numberOfStudents = number; else console.log('Invalid input: Was expecting type "number" but is actually: ' + typeof input); // In real life you would probably throw an error here instead of writing to console } } class High extends School { constructor(name, numberOfStudents, sportsTeam) { super(name, 'high', numberOfStudents); this._sportsTeam = sportsTeam; } get sportsTeam() { return this._sportsTeam; } } //create an instance of the class const alSmith = new High('Al E. Smith', 'string data', ['Baseball', 'Basketball', 'Volleyball', 'Track and Field']); console.log(alSmith); // try to change the number of students alSmith.numberOfStudents = 415; // sets numberOfStudents to 415 console.log(alSmith); //try to set as an incorrect value alSmith.numberOfStudents = 'apple'; //logs 'Invalid input: numberOfStudents must be set to a Number.' as expected. console.log(alSmith);

That makes sense, thanks for your help.

So, just to clarify the this.numberOfStudents on line 7 actually calls the setter on line 12 and passes it the numStudents argument. The setter then sets this._numberOfStudents on line 6 with numStudents if it doesn’t throw an error?

Thanks, I always get confused about this!

1 Like

You got it. I should have made that more clear with some comments in the code.

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.