Last active
March 21, 2024 09:11
-
-
Save getify/3b4f46cdd0b204eb03f2ba36e84e5948 to your computer and use it in GitHub Desktop.
an illustration (non-trivial example) of many newer JS class features
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// abstract class, not intended to be instantiated directly | |
class CalendarItem { | |
static #UNSET = Symbol("unset") | |
static #isUnset(v) { | |
return v === this.#UNSET; | |
} | |
static { | |
for (let [idx,msg] of [ | |
"ID is already set.", | |
"ID is unset.", | |
"Don't instantiate 'CalendarItem' directly.", | |
].entries()) { | |
this[`ERROR_${(idx+1)*100}`] = msg; | |
} | |
} | |
static isSameItem(item1,item2) { | |
if (#ID in item1 && #ID in item2) { | |
return item1.#ID === item2.#ID; | |
} | |
else { | |
return false; | |
} | |
} | |
#ID = CalendarItem.#UNSET | |
#setID(id) { | |
if (CalendarItem.#isUnset(this.#ID)) { | |
this.#ID = id; | |
} | |
else { | |
throw new Error(CalendarItem.ERROR_100); | |
} | |
} | |
description = null | |
startDateTime = null | |
constructor() { | |
// enforcing: abstract class, no direct instantiation | |
if (new.target !== CalendarItem) { | |
let id = Math.round(Math.random() * 1e9); | |
this.#setID(id); | |
} | |
else { | |
throw new Error(CalendarItem.ERROR_300); | |
} | |
} | |
getID() { | |
if (!CalendarItem.#isUnset(this.#ID)) { | |
return this.#ID; | |
} | |
else { | |
throw new Error(CalendarItem.ERROR_200); | |
} | |
} | |
getDateTimeStr() { | |
if (this.startDateTime instanceof Date) { | |
return this.startDateTime.toUTCString(); | |
} | |
} | |
summary() { | |
console.log(`(${ | |
this.getID() | |
}) ${ | |
this.description | |
} at ${ | |
this.getDateTimeStr() | |
}`); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Reminder extends CalendarItem { | |
#complete = false; // <-- no ASI, semicolon needed | |
[Symbol.toStringTag] = "Reminder" | |
constructor(description,startDateTime) { | |
super(); | |
this.description = description; | |
this.startDateTime = startDateTime; | |
} | |
isComplete() { | |
return !!this.#complete; | |
} | |
markComplete() { | |
this.#complete = true; | |
} | |
summary() { | |
if (this.isComplete()) { | |
console.log(`(${this.getID()}) Complete.`); | |
} | |
else { | |
super.summary(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Meeting extends CalendarItem { | |
#getEndDateTimeStr() { | |
if (this.endDateTime instanceof Date) { | |
return this.endDateTime.toUTCString(); | |
} | |
} | |
endDateTime = null; // <-- no ASI, semicolon needed | |
[Symbol.toStringTag] = "Meeting" | |
constructor(description,startDateTime,endDateTime) { | |
super(); | |
this.description = description; | |
this.startDateTime = startDateTime; | |
this.endDateTime = endDateTime; | |
} | |
getDateTimeStr() { | |
return `${ | |
super.getDateTimeStr() | |
} - ${ | |
this.#getEndDateTimeStr() | |
}`; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var callMyParents = new Reminder( | |
"Call my parents to say hi", | |
new Date("July 7, 2022 11:00:00 UTC") | |
); | |
callMyParents.toString(); | |
// [object Reminder] | |
callMyParents.summary(); | |
// (586380912) Call my parents to say hi at | |
// Thu, 07 Jul 2022 11:00:00 GMT | |
callMyParents.markComplete(); | |
callMyParents.summary(); | |
// (586380912) Complete. | |
callMyParents instanceof Reminder; | |
// true | |
callMyParents instanceof CalendarItem; | |
// true | |
callMyParents instanceof Meeting; | |
// false | |
var interview = new Meeting( | |
"Job Interview: ABC Tech", | |
new Date("June 23, 2022 08:30:00 UTC"), | |
new Date("June 23, 2022 09:15:00 UTC") | |
); | |
interview.toString(); | |
// [object Meeting] | |
interview.summary(); | |
// (994337604) Job Interview: ABC Tech at Thu, | |
// 23 Jun 2022 08:30:00 GMT - Thu, 23 Jun 2022 | |
// 09:15:00 GMT | |
interview instanceof Meeting; | |
// true | |
interview instanceof CalendarItem; | |
// true | |
interview instanceof Reminder; | |
// false | |
Reminder.isSameItem(callMyParents,callMyParents); | |
// true | |
Meeting.isSameItem(callMyParents,interview); | |
// false |
thank you @getify
static #UNSET = Symbol("unset")
What do the hashes signify? Please kindly link to MDN article.
if (new.target !== CalendarItem) {
From where does new
come?
Thanks in advance
What do the hashes signify?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields
From where does
new
come?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new.target
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
wow it's awesome tutorial ❤ i love it
thank you @getify