Skip to content

Commit 25c4059

Browse files
committedJul 16, 2022
objects-classes, ch3: adding a bit more to the final full 'class' example
1 parent ebac5cc commit 25c4059

File tree

1 file changed

+47
-9
lines changed

1 file changed

+47
-9
lines changed
 

‎objects-classes/ch3.md

+47-9
Original file line numberDiff line numberDiff line change
@@ -1170,6 +1170,18 @@ class CalendarItem {
11701170
static #isUnset(v) {
11711171
return v === this.#UNSET;
11721172
}
1173+
static #error(num) {
1174+
return this[`ERROR_${num}`];
1175+
}
1176+
static {
1177+
for (let [idx,msg] of [
1178+
"ID is already set.",
1179+
"ID is unset.",
1180+
"Don't instantiate 'CalendarItem' directly.",
1181+
].entries()) {
1182+
this[`ERROR_${(idx+1)*100}`] = msg;
1183+
}
1184+
}
11731185
static isSameItem(item1,item2) {
11741186
if (#ID in item1 && #ID in item2) {
11751187
return item1.#ID === item2.#ID;
@@ -1185,7 +1197,7 @@ class CalendarItem {
11851197
this.#ID = id;
11861198
}
11871199
else {
1188-
throw new Error("ID is already set");
1200+
throw new Error(CalendarItem.#error(100));
11891201
}
11901202
}
11911203

@@ -1198,15 +1210,15 @@ class CalendarItem {
11981210
this.#setID(id);
11991211
}
12001212
else {
1201-
throw new Error("Don't instantiate 'CalendarItem' directly.");
1213+
throw new Error(CalendarItem.#error(300));
12021214
}
12031215
}
12041216
getID() {
12051217
if (!CalendarItem.#isUnset(this.#ID)) {
12061218
return this.#ID;
12071219
}
12081220
else {
1209-
throw new Error("ID is unset");
1221+
throw new Error(CalendarItem.#error(200));
12101222
}
12111223
}
12121224
getDateTimeStr() {
@@ -1226,8 +1238,9 @@ class CalendarItem {
12261238
}
12271239

12281240
class Reminder extends CalendarItem {
1229-
#complete = false
1241+
#complete = false; // <-- no ASI, semicolon needed
12301242

1243+
[Symbol.toStringTag] = "Reminder"
12311244
constructor(description,startDateTime) {
12321245
super();
12331246

@@ -1251,14 +1264,15 @@ class Reminder extends CalendarItem {
12511264
}
12521265

12531266
class Meeting extends CalendarItem {
1254-
endDateTime = null
1255-
12561267
#getEndDateTimeStr() {
12571268
if (this.endDateTime instanceof Date) {
12581269
return this.endDateTime.toUTCString();
12591270
}
12601271
}
12611272

1273+
endDateTime = null; // <-- no ASI, semicolon needed
1274+
1275+
[Symbol.toStringTag] = "Meeting"
12621276
constructor(description,startDateTime,endDateTime) {
12631277
super();
12641278

@@ -1276,11 +1290,11 @@ class Meeting extends CalendarItem {
12761290
}
12771291
```
12781292

1279-
Take some time to read and digest those `class` definitions. Note which of the `class` features from this chapter that you see being used.
1293+
Take some time to read and digest those `class` definitions. Did you spot most of the `class` features we talked about in this chapter?
12801294

12811295
| NOTE: |
12821296
| :--- |
1283-
| One question you may have: why didn't I move the common logic of `description` and `startDateTime` setting from both subclass constructors into the single base constructor. This is a nuanced point, but it's not my intention that `CalendarItem` ever be directly instantiated; it's what in class-oriented terms we refer to as an "abstract class". That's why I'm using `new.target` to throw an error if the `CalendarItem` class is ever directly instantiated! |
1297+
| One question you may have: why didn't I move the repeated logic of `description` and `startDateTime` setting from both subclass constructors into the single base constructor? This is a nuanced point, but it's not my intention that `CalendarItem` ever be directly instantiated; it's what in class-oriented terms we refer to as an "abstract class". That's why I'm using `new.target` to throw an error if the `CalendarItem` class is ever directly instantiated! So I don't want to imply by signature that the `CalendarItem(..)` constructor should ever be directly used. |
12841298

12851299
Let's now see these three classes in use:
12861300

@@ -1289,25 +1303,49 @@ var callMyParents = new Reminder(
12891303
"Call my parents to say hi",
12901304
new Date("July 7, 2022 11:00:00 UTC")
12911305
);
1306+
callMyParents.toString();
1307+
// [object Reminder]
12921308
callMyParents.summary();
12931309
// (586380912) Call my parents to say hi at
12941310
// Thu, 07 Jul 2022 11:00:00 GMT
1295-
12961311
callMyParents.markComplete();
12971312
callMyParents.summary();
12981313
// (586380912) Complete.
1314+
callMyParents instanceof Reminder;
1315+
// true
1316+
callMyParents instanceof CalendarItem;
1317+
// true
1318+
callMyParents instanceof Meeting;
1319+
// false
1320+
12991321

13001322
var interview = new Meeting(
13011323
"Job Interview: ABC Tech",
13021324
new Date("June 23, 2022 08:30:00 UTC"),
13031325
new Date("June 23, 2022 09:15:00 UTC")
13041326
);
1327+
interview.toString();
1328+
// [object Meeting]
13051329
interview.summary();
13061330
// (994337604) Job Interview: ABC Tech at Thu,
13071331
// 23 Jun 2022 08:30:00 GMT - Thu, 23 Jun 2022
13081332
// 09:15:00 GMT
1333+
interview instanceof Meeting;
1334+
// true
1335+
interview instanceof CalendarItem;
1336+
// true
1337+
interview instanceof Reminder;
1338+
// false
1339+
1340+
1341+
Reminder.isSameItem(callMyParents,callMyParents);
1342+
// true
1343+
Meeting.isSameItem(callMyParents,interview);
1344+
// false
13091345
```
13101346

1347+
Admittedly, some bits of this example are a little contrived. But honestly, I think pretty much all of this is plausible and reasonable usages of the various `class` features.
1348+
13111349
By the way, there's probably a million different ways to structure the above code logic. I'm by no means claiming this is the *right* or *best* way to do so. As an exercise for the reader, try your hand and writing it yourself, and take note of things you did differently than my approach.
13121350

13131351
[^POLP]: *Principle of Least Privilege*, https://en.wikipedia.org/wiki/Principle_of_least_privilege, 15 July 2022.

0 commit comments

Comments
 (0)
Failed to load comments.