define-object

A bit of sugar for defining Objects and their prototypes.

npm install define-object
4 downloads in the last week
16 downloads in the last month

defineObject

A bit of sugar for defining JavaScript Objects and their prototypes.

  • A small wrapper around creating JavaScript objects, does not try turn JavaScript into something it's not. (ie classes)
  • Define objects without having to deal with the awkward and verbose syntax found in ES3 & ES5.
  • Painless inheritance, initialization and static methods of the parent class are automatically carried over to the child class.
  • After inheritance, the constructor property on the prototype correctly points to it's constructor, unlike common js inheritance patterns.
  • Provides a simple mechanism for mixins.
  • What gets created is a plain javascript constructor

Usage


  //Create a base class with some default methods
  var Base = defineObject({
    hello: function() {
      console.log("hello world!");
    }
  });

  //Extend from the base class
  var Animal = Base.extend({
    //a initialization method with side-effects
    //that luckily will not get called when the Animal object is extended from
    __init__: function() {
      this.launchRockets();
    },
    sound: 'silence',
    weight: 0,
    vocalize: function() {
      console.log(this.sound);
    }
  });

  //Create a logger method which will be used as a mixin in our example
  //any object, or constructor can be used as a mixin
  var Logger = Base.extend({
    __init__: function() {
      this.logHistory = [];
    },
    log : function(msg) {
    this.logHistory.push(msg);
    console.log(msg)
    }

  });

  //Define the Dog object extending from Animal while mixing in Logger.
  var Dog = Animal.extend({
    __init__ : function(weight) {
      this.weight = weight;
      //Dog.__super.__init__.call(this); -- if you need to have access to the Animal initialization method
    },
    sound : 'woof',
    vocalize : function() {
      Dog.__super__.vocalize.call(this); // Calling 'super' methods remains about the same.
      this.log("dog is vocalizing");
    },
    drool: function() {
      console.log("I want what you're having.");
      this.log("dog is drooling")
    }
  }).mixin(Logger);

  var dog = new Dog();
  dog.hello();
  dog.vocalize();
  dog.drool();
  console.log("History", dog.logHistory);

  console.log( dog instanceof Dog ); //true
  console.log( dog instanceof Animal); //true
  console.log( dog.constructor === Dog); //true
  console.log( dog instanceof Logger); //false

Extending from plain js constructors

You can use defineObject to extend from plain javascript constructors using defineObject.extend


var Plain = function() {
  this.foo = 'bar';
};

Plain.prototype.bar = 'foo';

var Ext = defineObject.extend(Plain, {
    fizz: 'fuzz'
}).mixin({'fud' : 'foo'});

var obj = Ext.create();

console.log(obj instanceof Plain);
console.log(obj.foo, obj.bar, obj.fizz, obj.fud);

Mixins

Mixins can take the form of either an object or a constructor.

if an object is used the object properties are merged into the target prototype, if an init method is defined than it will on instantiation.


var O = defineObject()
  .mixin({
    __init__ : function() {
      this.msg = "hello world!";
    },
    print : function() {
      console.log(this.msg);
    }
  })
  .mixin({
    __init__ : function() {
      this.value = "hello earth!";
    },
    show : function() {
      console.log(this.value);
    }
  });

var o = new O();

o.print() //"hello world!";
o.show() //"hello earth!";

If a constructor is passed into the mixin method, the init method on the prototype will be used upon instantiation. If an init method does not exists, the constructor method itself will be used.

Static Methods

Static methods can be defined by passing in a second object literal to defineObject or extend;


var O = defineObject({
    instanceProp: 'foo'
  },
  {
    staticProp: 'bar'
  });

console.log(O.staticProp)

Note: defineOjbect will not allow you to redefine existing static properties, an exception will be thrown.

[ES5 ONLY] Properties

calling the 'properties' method on an object definition will simply pass the assigned literal to Object.defineProperties upon the creation of an object.

See: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperties


  var O = defineObject()
    .properties({
      field : {
            value : 'value',
            writable : false
          }
        }
    });

  var o = O.create();
  console.log(o.field);
  o.field = 'error'; //error

Chainable style

Objects can be defined in a more chainable style as well:

  Dog = Animal.extend()
    .methods({...})
    .statics({...})
    .mixin(...)
    .mixin(...)
    .properties({...})

Where 'methods' and 'statics' replace the first two arguments of the extend/defineOjbect function. Both functions can also be used to extend the prototype/static methods of an Object.

npm loves you