Skip to content

Instantly share code, notes, and snippets.

@OleksiyRudenko
Last active August 29, 2022 06:19
Show Gist options
  • Save OleksiyRudenko/672d39b08d9d0da4e179aca49876c58b to your computer and use it in GitHub Desktop.
Save OleksiyRudenko/672d39b08d9d0da4e179aca49876c58b to your computer and use it in GitHub Desktop.
// based on parts of: http://exploringjs.com/es6/ch_classes.html
const methodName = 'myMethod'; // for computed method names
// class
class Point {
// publicProperty = defaultValue; // NB! Unsupported yet? No assignment - no property!
publicProperty = 1; // need no constructor if it is only to initialize class properties
constructor(x, y) {
this.x = x;
this.y = y;
this._privateProperty = 0; // though it's a naming convention only
}
; // OK, ignored; other delimiters forbidden
handleChange = (e) => e.target; // bound to `this`
handleClick = ({target}) => target; // bound to `this`
toString() { // prototypical method
return `(${this.x}, ${this.y})`;
}
getConstructorName() {
return this.constructor.name; // Point or child class name
}
static staticMethod() { // static; inheritable
return this.name; // not this.constructor.name since this method is static
}
static get ZERO() { // static getter; see also approach of assigning static property below
return new Point(0, 0);
}
// getter & setters; used as obj.prop
get coords() { return [this.x, this.y]; }
set coords(coords) { [this.x, this.y] = coords; }
// computed method names
['my'+'Method']() {}
[methodName]() {} // see const above class def
// private data: http://exploringjs.com/es6/ch_classes.html#sec_private-data-for-classes
// 1. scoping
// 2. naming convention
// 3. WeakMap
// 4. Symbol
// other
logStaticProp() {
Point.ZERO(); // employ inner name
}
}
Point.ZERO = new Point(0,0); // static property
// Read-only property
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
// (what about class level static?)
obj = Object.defineProperty(obj, prop, descriptor); // descriptor - as per link above
// subclass
class ColorPoint extends Point {
constructor(x, y, color) {
super(x,y); // call super() and call it before using `this`
this.color = color;
}
/*
Default constructor for derived class:
constructor(...args) {
super(...args);
}
*/
toString() {
return super.toString() + ' in ' + this.color;
}
static staticMethod() { // extend/replace static methods
return 'both of types ' + this.name + ' and ' + super.staticMethod();
}
}
// see more classes after next section
// usage
// you cannot call fn that uses class before class defined
const cp = new ColorPoint(25, 8, 'green');
cp.toString();
cp instanceof ColorPoint; // true
cp instanceof Point; // true
Object.getPrototypeOf(ColorPoint) == Point; // true
typeof Point; // 'function'
Point(); // ERROR! TypeError: Classes can’t be function-called
Point.staticMethod();
// anonymous class expression
const myClassA = class {
// ...
};
const instA = new MyClassA();
// named class where class name is visible only inside it
const myClassB = class Me {
getClassName() {
return Me.name;
}
};
const instB = new MyClassB();
inst.getClassName(); // Me
Me.name; // ReferenceError: Me is not defined
// special methods
class IterableArguments {
constructor (...args) {
this.args = args;
}
// make class iterable (via for-of loops etc)
[Symbol.iterator]() {
}
// generator
* [Symbol.iterator]() {
for (const arg of this.args) {
yield arg;
}
}
}
// usage
for (const x of new IterableArguments('hello','world')) {
console.log(x);
}
// special extensions - Exception Class
class MyError extends Error {
}
throw new MyError('Smth happened!');
// special arrays
// Note that subclassing Array is usually not the best solution.
// It’s often better to create your own class (whose interface you control)
// and to delegate to an Array in a private property.
class Stack extends Array {
get top() {
return this[this.length - 1];
}
}
var stack = new Stack();
stack.push(1);
stack.push(2);
stack.top; // 2
stack.length; // 2
// Multiple inheritance
class Person {}
class Storage { save(db){} }
class Validation { validate(schema){} }
class Employee extends Storage, Validation, Person { } // Error!
class Person {}
const Storage = Sup => class extends Sup {
save(database) { }
};
const Validation = Sup => class extends Sup {
validate(schema) { }
};
class Employee extends Storage(Validation(Person)) {
}
// Function.prototype.apply() ===
function instantiate(TheClass, args) {
return new TheClass(...args);
}
// or
function instantiate(TheClass, args) {
return Reflect.construct(TheClass, args);
}
/* =================================== further reading ===============
http://exploringjs.com/es6/ch_classes.html#sec_private-data-for-classes
https://github.com/rwaldron/tc39-notes/blob/master/es6/2015-01/jan2015-allen-slides.pdf
*/
// class
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return `(${this.x}, ${this.y})`;
}
static staticMethod() {
return Point.name;
}
static get ZERO() {
return new Point(0, 0);
}
get coords() { return `(${this.x}, ${this.y})`; }
set coords(coords) { this.x = coords[0]; this.y = coords[1]; }
getConstructorName() { return this.constructor.name; }
}
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y);
this.color = color;
}
toString() {
return super.toString() + ' in ' + this.color;
}
static staticMethod() {
return 'both of types ' + this.name + ' and ' + super.staticMethod();
}
}
const p = new Point(1, 3);
const cp = new ColorPoint(25, 8, 'green');
[p, cp, Object.keys(cp)].forEach(console.dir);
/*
// Below are only relevant properties from console.dir output.
// Repeating content of objects replaced with {{ObjectName}} notation.
// Getters are resolved.
Point
x: 1
y: 3
coords: "(1, 3)"
__proto__:
constructor: class Point
ZERO: Point
arguments: (...)
caller: (...)
length: 2
name: "Point"
prototype:
constructor: class Point {{class Point}}
coords: "(undefined, undefined)"
getConstructorName: ƒ getConstructorName()
toString: ƒ toString()
get coords: ƒ coords()
set coords: ƒ coords(coords)
staticMethod: ƒ staticMethod()
get ZERO: ƒ ZERO()
coords: "(1, 3)"
getConstructorName: ƒ getConstructorName()
toString: ƒ toString()
get coords: ƒ coords()
set coords: ƒ coords(coords)
ColorPoint
color: "green"
x: 25
y: 8
coords: "(25, 8)"
__proto__: Point
constructor: class ColorPoint
ZERO: Point
arguments: (...)
caller: (...)
length: 3
name: "ColorPoint"
prototype: Point {constructor: ƒ, toString: ƒ}
constructor: class ColorPoint
ZERO: Point
arguments: (...)
caller: (...)
length: 3
name: "ColorPoint"
prototype: Point {constructor: ƒ, toString: ƒ}
constructor: class ColorPoint {{class ColorPoint}}
coords: (...)
toString: ƒ toString()
__proto__:
constructor: class Point {{class Point}}
coords: "(undefined, undefined)"
getConstructorName: ƒ getConstructorName()
toString: ƒ toString()
get coords: ƒ coords()
set coords: ƒ coords(coords)
staticMethod: ƒ staticMethod()
__proto__: class Point
ZERO: Point
arguments: (...)
caller: (...)
length: 2
name: "Point"
prototype: {constructor: {{class Point}}, toString: ƒ, getConstructorName: ƒ}
staticMethod: ƒ staticMethod()
get ZERO: ƒ ZERO()
coords: "(undefined, undefined)"
toString: ƒ toString()
__proto__: Object
constructor: class Point {{class Point}}
coords: "(undefined, undefined)"
getConstructorName: ƒ getConstructorName()
toString: ƒ toString()
get coords: ƒ coords()
set coords: ƒ coords(coords)
staticMethod: ƒ staticMethod()
__proto__: class Point
ZERO: Point
arguments: (...)
caller: (...)
length: 2
name: "Point"
prototype: {constructor: {{class Point}}, toString: ƒ, getConstructorName: ƒ}
staticMethod: ƒ staticMethod()
get ZERO: ƒ ZERO()
coords: "(25, 8)"
toString: ƒ toString()
__proto__: Object
constructor: class Point {{class Point}}
coords: "(25, 8)"
getConstructorName: ƒ getConstructorName()
toString: ƒ toString()
get coords: ƒ coords()
set coords: ƒ coords(coords)
// Object.keys() lists only own iterable properties
Object.keys(cp) => Array(3)
0: "x" // what?! own property?
1: "y" // what?! own property?
2: "color"
length: 3
*/
@OleksiyRudenko
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment