Zorgatone
4/6/2016 - 12:58 PM

Inheritable Top-level Classes

Inheritable Top-level Classes

"use strict";

Object.defineProperty(window, "BaseObject", {
  value: (() => {
    let nil = Object.freeze(Object.create(null));

    Object.defineProperty(window, "Nil", {
      value: (() => {
        function Nil() {}
        Nil.prototype = nil;

        return Nil;
      })(),
      writable: false,
      enumerable: false,
      configurable: false
    });

    // (nil !== nil) => true
    // (nil instanceof Nil) => true
    // (nil.prop = "val"; nil.prop) => undefined
    Object.defineProperty(window, "nil", {
      get: function () {
        return Object.freeze(new Nil());
      },
      set: function () {
        throw new Error("Cannot overwrite nil");
      },
      enumerable: false,
      configurable: false
    });

    class BaseObject extends Nil {
      constructor() {
        super();

        // non-enumerable [fixes JSON.stringify bug]
        Object.defineProperty(this, "__proto__", {
          value: BaseObject.prototype,
          writable: false,
          enumerable: false,
          configurable: false
        });
      }

      toString() {
        return `[object ${this.constructor.name}]`;
      }

      toJson() {
        return JSON.stringify(Object.assign({
          "__class__": this.constructor.name
        }, this));
      }
    }

    BaseObject.fromJson = obj => {
      return Object.assign(new BaseObject(), JSON.parse(obj));
    };

    return BaseObject;
  })(),
  writable: false,
  enumerable: false,
  configurable: false
});

class Entity extends BaseObject {
  constructor(name = "Steve") {
    super();

    this.name = name;
  }

  sayHi() {
    console.log(`Hi! My name is ${this.name}`);
  }
}

// Entity.fromJson = undefined;
Entity.fromJson = obj => {
  let parsed = JSON.parse(obj);
  delete parsed["__class__"];
  return Object.assign(new Entity(parsed && parsed.name), parsed);
};