JavaScript

Last Updated: 2/2/2023

ES 6 Classes

  • From ES6, or ES 2015 there is a new way to create objects and implement inheritance using classes.
  • These classes are not like classes in languages like C# and Java, they are essentially syntactic sugar over prototypical inheritance.
  • Constructor is a special method that is used to initialize objects
  • Methods added inside the class are added to the prototype
  • Methods inside the constructor are not added to the prototype
  • You can define classes using a declaration or an expression syntax. Class declarations or class expressions are not hoisted.
class Circle {
    constructor(radius) {
        this.radius = radius;
        this.move = function() {}
    }

    draw() {
        console.log("draw");
    }
}

const c1 = new Circle(10);

https://babeljs.io/

Static Methods

  • In classical object-oriented languages, you have two types of methods. Instance methods and static methods.
  • Instance methods are available on an instance of a class which is an object,
  • Static methods are available on the class itself and not on the object instance. You often use them to create utility functions that are not specific to a given object.
class Circle {
    constructor(radius) {
        this.radius = radius;
        this.move = function() {}
    }

    draw() {
        console.log("draw");
    }

    static parse(radius) {
        return new Circle(radius);
    }
}
const c1 = Circle.parse(10);

this keyword

  • When you call a method on the object, this will refer to the object
  • When you call as a standalone function, this will refer to window or undefine in strict mode
class Circle {
    constructor(radius) {
        this.radius = radius;
        this.move = function() {}
    }

    draw() {
        console.log(this, "draw");
    }

    // static method    
    static parse(radius) {
        return new Circle(radius);
    }
}

const c1 = new Circle(10);
c1.draw(); //this refers to c1


const draw = c1.draw;
draw(); //this refers to undefined

Inheritance

  • Use extends keyword to define inheritance
  • If you have a constructor in the parent class, and then you add a constructor in the child class, inside of the child constructor you should make sure to call the parent constructor first, to initialize the base object
class Shape {
     constructor(color) {
         this.color = color;
     }

     draw() {
         console.log("shape draw", this.color, this.radius);
     }
 }

 class Circle extends Shape {
     constructor(radius, color) {
         super(color);
         this.radius = radius;
     }

     draw() {
         super.draw();
         console.log("circle draw");
     }
 }

 const c1 = new Circle(10, "red");
 c1.draw();

Getters and Setters

const _radius = new WeakMap();
const _move = new WeakMap();

class Circle {
    constructor(radius) {
        _radius.set(this, radius);
        _move.set(this, () => {
            console.log(this, "move");
        })
    }

    draw() {
        console.log(_radius.get(this));
        _move.get(this)();
    }

    get radius() {
        return _radius.get(this);
    }
    set radius(value) {
        _radius.set(this, value);
    }
}

Symbol

  • In ES6 you have a new primitive type called Symbol.
  • Symbol is a function which generates a unique identifier/value.
  • You can use symbol as a member name instead of a string to define private property and method

Implementing Private Members with Symbol

let _color = Symbol();
let _rotate = Symbol();
let _paint = Symbol();

class Circle {
    constructor(radius) {
        this.radius = radius;
        this.move = function() {}
        this[_color] = "red";
        this[_rotate] = function() {
            console.log(this.radius, "rotate instance");    
        }
    }

    [_paint]() {
        console.log(this.radius, "paint prototype");
    }
    
    draw() {
        console.log(this.radius, "draw");
        this[_paint]();
    }

    // static method    
    static parse(radius) {
        return new Circle(radius);
    }
}

WeakMaps

  • A WeakMap is essentially a dictionary where keys are objects and values can be anything
  • You call them WeakMaps is because the keys are the weak. So if there are no references to these keys, they will be garbage collected.

Implementing Private Members with WeakMaps

const _radius = new WeakMap();
const _move = new WeakMap();

class Circle {
	constructor(radius) {
	    _radius.set(this, radius);
	    _move.set(this, () => {
	        console.log(this, "move");
	    })
	}

	draw() {
	    console.log(_radius.get(this));
	    _move.get(this)();
	}
}

Getters and Setters

Using Object Define Property

class Circle {
    constructor(radius) {
        _radius.set(this, radius);

        Object.defineProperty(this, "radius", {
            get: function() {
                return _radius.get(this);
            },
            set: function(value){
                if(value < 0)
                    throw "invalid";
                _radius.set(this, value);
            }
        })    
    }
}