Potions - michbuett/alchemy.js GitHub Wiki

Potions are the prototypes of any object you create when using alchemy.js. Yes, it is prototype based. Hell, this is JavaScript! There is no Class, Klass, Clazz or anything unnatural like that. alchemy.js is working with prototypes as it was meant to be. You can define new potions with

alchemy.formula.add({
  name: 'MyType',
  extend: 'SomeSuperType',
  overrides: {
    // custom properties and methods
    ...
  }
});

After that you can access the new potion using alchemy('MyType'). The object is created in the moment of the first access so the order of the declaration does not matter, i.e you can define MyType before defining SomeSuperType. To avoid conflicts with other frameworks alchemy.js does not alter native objects.

The name is a required property when defining potions via formulas. The property extend defines the super type. By default this is core.MateriaPrima.

Super

It also provides a convenient super reference. Every method that should override a method of its super type but also wants to use the origin can be declared as a "magic" creator method. I.E. it should be a function that returns the actual type method. The name of the creator method has to be "hocuspocus" so alchemy.js knows what to do. For Example:

alchemy.addFormula({
  name: 'MyType',
  overrides: {
    foo: function () {      
      return 'foo';
    }
  }
});

alchemy.addFormula({
  name: 'MySubType',
  extend: 'MyType',
  overrides: {
    foo: function hocuspocus(_super) {
      return function () {      
        return _super.call(this) + ' - bar';
      };
    }
  }
});

alchemy('MySubType').foo() // returns "foo - bar"

Aside from defining potions you can extend any object any time, e.g

var obj = {
  foo: function () {
    return 'foo';
  }
};

alchemy.override(obj, {
  foo: function hocuspocus(_super) {
    return function () {
      return _super() + ' - bar';
    };
  }
});

obj.foo(); // will return "foo - bar"

I tried a lot of different implementations of _super and I think this is it:

  • it does not depend on the deprecated arguments.caller
  • it does not depend on the non-standard Function.prototype.caller
  • it is much faster than John Resig's Simple JavaScript Inheritance
  • it preserves the closure scope (unklike previous implementations)

Brew it!

You can create instances of a prototype using a factory pattern, e.g.

var myIntance = MyType.brew({
  cfg1: 'foo',
  cfg2: 'bar',
  ...
});

In contrast to the native Object.create the arguments are passed to the constructor method of a new potion instance.