I’m working through the School Catalogue project in the Learn Intermediate JavaScript course, and have stumbled onto a bit of a roadblock.
The PrimarySchool instance (on Line 71) is passing a string to the PrimarySchool class constructor (Line 47), which in turn passes it up to the School class constructor (Line 3) to set the numberOfStudents property. However, it doesn’t seem to trigger the console message on Line 25 which is meant to determine if the input is invalid (i.e: not a number).
Any idea what’s going on here?
Apologies in advance for any miscommunication or incorrect terms used.
// Parent Class
class School {
constructor(name, level, numberOfStudents) {
this._name = name;
this._level = level;
this._numberOfStudents = numberOfStudents;
}
// Getters
get name() {
return this._name;
}
get level() {
return this._level;
}
get numberOfStudents() {
return this._numberOfStudents;
}
// Setters
set numberOfStudents(number) {
if (number.isNaN()) {
console.log("Invalid input: numberOfStudents must be set to a number.");
} else {
this._numberOfStudents = number;
}
}
quickFacts() {
console.log(
`${this.name} educates ${this.numberOfStudents} students at the ${this.level} school level.`
);
}
static pickSubstituteTeacher(substituteTeachers) {
const randomNumber = Math.floor(
Math.random() * (substituteTeachers.length - 1)
);
return substituteTeachers[randomNumber];
}
}
// Primary School Class
class PrimarySchool extends School {
constructor(name, numberOfStudents, pickupPolicy) {
super(name, "primary", numberOfStudents);
this._pickupPolicy = pickupPolicy;
}
// Getters
get pickupPolicy() {
return this._pickupPolicy;
}
}
// High School Class
class HighSchool extends School {
constructor(name, numberOfStudents, sportsTeams) {
super(name, "high", numberOfStudents);
this._sportsTeams = sportsTeams;
}
// Getters
get sportsTeams() {
return this._sportsTeams;
}
}
// Primary School Creation
const lorraineHansbury = new PrimarySchool(
"Lorraine Hansbury",
"Not a Number",
"Students must be picked up by a parent, guardian, or a family member over the age of 13."
);
lorraineHansbury.quickFacts();
// High School Creation
const alSmith = new HighSchool("Al E. Smith", 415, [
"Baseball",
"Basketball",
"Volleyball",
"Track and Field",
]);
console.log(alSmith.sportsTeams);
// Static Method
const substitute = School.pickSubstituteTeacher([
"Jamal Crawford",
"Lou Williams",
"J. R. Smith",
"James Harden",
"Jason Terry",
"Manu Ginobli",
]);
In the numberOfStudents setter for the School class,
I think that should be isNaN(number)
or Number.isNaN(number)
otherwise it’ll just check the .isNaN property of the number variable;
and if it doesn’t have one, number.isNaN would be undefined (which would work like false in that if-statement condition).
The odd thing is, the setup is nearly completely identical to the video guide.
Is there something which has been overlooked here?
EDIT: It appears that the following code works, although I’m not so sure why removing the prepended '_' in the School constructor solves this. I also changed the setter to check for typeof instead.
// Parent Class
class School {
constructor(name, level, numberOfStudents) {
this._name = name;
this._level = level;
this.numberOfStudents = numberOfStudents;
}
// Getters
get name() {
return this._name;
}
get level() {
return this._level;
}
get numberOfStudents() {
return this._numberOfStudents;
}
// Setters
set numberOfStudents(number) {
if (typeof number === 'string') {
this._numberOfStudents = '[UNDEFINED]';
console.log("Invalid input: numberOfStudents must be set to a number.");
} else {
this._numberOfStudents = number;
}
}
quickFacts() {
console.log(
`${this.name} educates ${this.numberOfStudents} students at the ${this.level} school level.`
);
}
static pickSubstituteTeacher(substituteTeachers) {
const randomNumber = Math.floor(
Math.random() * (substituteTeachers.length - 1)
);
return substituteTeachers[randomNumber];
}
}
// Primary School Instance
class PrimarySchool extends School {
constructor(name, numberOfStudents, pickupPolicy) {
super(name, "primary", numberOfStudents);
this._pickupPolicy = pickupPolicy;
}
// Getters
get pickupPolicy() {
return this._pickupPolicy;
}
}
// High School Instance
class HighSchool extends School {
constructor(name, numberOfStudents, sportsTeams) {
super(name, "high", numberOfStudents);
this._sportsTeams = sportsTeams;
}
// Getters
get sportsTeams() {
return this._sportsTeams;
}
}
// Primary School Creation
const lorraineHansbury = new PrimarySchool(
"Lorraine Hansbury",
"Not a Number",
"Students must be picked up by a parent, guardian, or a family member over the age of 13."
);
lorraineHansbury.quickFacts();
// High School Creation
const alSmith = new HighSchool("Al E. Smith", 415, [
"Baseball",
"Basketball",
"Volleyball",
"Track and Field",
]);
console.log(alSmith.sportsTeams);
// Static Method
const substitute = School.pickSubstituteTeacher([
"Jamal Crawford",
"Lou Williams",
"J. R. Smith",
"James Harden",
"Jason Terry",
"Manu Ginobli",
]);
The issue seems to be the constructor, not the setter.
details
You set up a new instance of PrimarySchool here:
const lorraineHansbury = new PrimarySchool(
"Lorraine Hansbury",
"Not a Number",
"Students must be picked up by a parent, guardian, or a family member over the age of 13."
);
This calls the constructor for PrimarySchool, not a setter for ._numberOfStudents
And the constructor for PrimarySchool uses the constructor for School.
You could check whether that argument/parameter is a number in the constructor.
class School {
constructor(name, level, numberOfStudents) {
this._name = name;
this._level = level;
if ((typeof numberOfStudents) == "number") {
this._numberOfStudents = numberOfStudents;
}
else {
this._numberOfStudents = 0;
}
}
So this works, but only if I remove the prepended '_' from this_numberOfStudents in the School constructor:
// Parent Class
class School {
constructor(name, level, numberOfStudents) {
this._name = name;
this._level = level;
this.numberOfStudents = numberOfStudents;
}
// Getters
get name() {
return this._name;
}
get level() {
return this._level;
}
get numberOfStudents() {
return this._numberOfStudents;
}
// Setters
set numberOfStudents(number) {
if (typeof number === 'string') {
this._numberOfStudents = '[invalid input]';
console.log("Invalid input: numberOfStudents must be set to a number.");
} else {
this._numberOfStudents = number;
}
}
quickFacts() {
console.log(
`${this.name} educates ${this.numberOfStudents} students at the ${this.level} school level.`
);
}
static pickSubstituteTeacher(substituteTeachers) {
const randomNumber = Math.floor(
Math.random() * (substituteTeachers.length - 1)
);
return substituteTeachers[randomNumber];
}
}
// Primary School Class
class PrimarySchool extends School {
constructor(name, numberOfStudents, pickupPolicy) {
super(name, "primary", numberOfStudents);
this._pickupPolicy = pickupPolicy;
}
// Getters
get pickupPolicy() {
return this._pickupPolicy;
}
}
// High School Class
class HighSchool extends School {
constructor(name, numberOfStudents, sportsTeams) {
super(name, "high", numberOfStudents);
this._sportsTeams = sportsTeams;
}
// Getters
get sportsTeams() {
return this._sportsTeams;
}
}
// Primary School Creation
const lorraineHansbury = new PrimarySchool(
"Lorraine Hansbury",
"Not a Number",
"Students must be picked up by a parent, guardian, or a family member over the age of 13."
);
lorraineHansbury.quickFacts();
// High School Creation
const alSmith = new HighSchool("Al E. Smith", 415, [
"Baseball",
"Basketball",
"Volleyball",
"Track and Field",
]);
console.log(alSmith.sportsTeams);
// Static Method
const substitute = School.pickSubstituteTeacher([
"Jamal Crawford",
"Lou Williams",
"J. R. Smith",
"James Harden",
"Jason Terry",
"Manu Ginobli",
]);
Once I add it back in, it stops working, which is another point of confusion for me.
I don’t get why we don’t include ‘levels’ in the subclasses constructor. In the previous exercise (build a library), we included ALL of the properties in the subclass’s constructor.
There’s only one level for each subclass here, so the level does not to be a parameter for the subclass constructions.
The .level for High School is "high" (for all such objects)
The .level for PrimarySchool is "primary" (for all such objects)
in the previous posts.