decl / examples

Example example

In each example, the object literal style is shown on the left, and the metaconstructor style is shown on the right.


// object literal

var ExampleThing = decl({ 
  //...
});

// "metaconstructor"

var ExampleThing = decl(function(){ 
  //...
});

Implicit constructor

There's no need to provide a constructor function in your declaration; it will automatically be created if omitted.


var Thing = decl({ 
  
  title: "thing",
  
  describe: function(){
    alert("Looks like a " + this.title + ".");
  }
  
});

var Thing = decl(function(){ 
  
  this.title = "thing";
  
  this.describe = function(){
    alert("Looks like a " + this.title + ".");
  };
  
});

var item = new Thing();

item.describe(); // "Looks like a thing."

item.title = "glass sculpture";

item.describe(); // "Looks like a glass sculpture."

Explicit constructor

You may provide an explicit constructor function in your declaration; it will be returned by decl.


var Animal = decl({ 
  
  species: "unknown critter",
  
  constructor: function(species) {
    if (species) {
      this.species = species;
    }
  },
  
  describe: function(){
    alert("Looks like a " + this.species);
  }
  
});

var Animal = decl(function(){ 
  
  this.species = "unknown critter";
  
  this.constructor = function(species) {
    if (species) {
      this.species = species;
    }
  };
  
  this.describe = function(){
    alert("Looks like a " + this.species);
  };
  
});

var donald = new Animal("duck");

donald.describe(); // "Looks like a duck"

Inheritance

decl makes prototypal inheritance easy. The metaconstructor style (right) offers a clean syntax for inheritance.


var Dog = decl({ 
  
  "decl-data": {extend: Animal},
  
  species: "dog"
  
});

var Dog = decl(function(){ 
  
  this.extend(Animal);
  
  this.species = "dog";
  
});

var rex = new Dog();

rex.describe(); // "Looks like a dog"

Implicit constructor + inheritance

In the previous example, no constructor was provided in the declaration, so decl created a wrapper for the parent constructor. Arguments may be passed to the child constructor just as they are passed to the parent constructor.


var fido = new Dog("hound");

fido.describe(); // "Looks like a hound"

Explicit constructor + inheritance

If you provide a constructor in the declaration, you may want to apply the parent constructor.

Calling this.extend within a metaconstructor returns a reference to the parent constructor's prototype.


var Toad = decl({ 
  
  "decl-data": {extend: Animal},
  
  species: "toad",
  
  constructor: function(species, habitat) {
    
    // apply the parent constructor
    Animal.apply(this, arguments);
    
    if (habitat) {
      this.habitat = habitat;
    }
  }
  
});

var Toad = decl(function(){ 

  var parent = this.extend(Animal);  
  
  this.species = "toad";
  
  this.constructor = function(species, habitat) {
  
    // apply the parent constructor
    parent.constructor.apply(this, arguments);
    
    if (habitat) {
      this.habitat = habitat;
    }
  };
  
});

Partial declaration

Declarations can be amended like this:


// more properties for Animal.prototype
decl({ 
  
  "decl-data": {augment: Animal},
  
  sound: "makes no sound",
  
  makeNoise: function() {
    alert("The " + this.species + " " + this.sound);
  }
  
});

// more properties for Animal.prototype
decl(function(){ 
  
  this.augment(Animal);
  
  this.sound = "makes no sound";
  
  this.makeNoise = function() {
    alert("The " + this.species + " " + this.sound);
  };
  
});

var critter = new Animal();
critter.sound = "growls";

critter.makeNoise(); // "The unknown critter growls"

Metadata

By default, decl stores information in a property of the declaration object named decl-data. The metaconstructor style abstracts this; there is no reason to worry about decl-data when using the metaconstructor style.

When using the object literal style, metadata must be stored in the decl-data property. The property name may be changed from decl-data to something else by setting decl.dataKey to a different value. This may be desirable if the object literal style is preferred.

Note that the decl-data property will never be copied from the declaration object into the prototype of the constructor, whether or not the property is renamed.



// "decl-data" is annoying to type, but shouldn't conflict with anything.

var Frog = decl(function(){ 
  "decl-data": {extend: Animal},
  species: "frog"
});

// Change decl's data storage property name.

decl.dataKey = "meta";

// This is easier to type. Your constructor prototypes can't have a property named "meta" now though.

var Gopher = decl(function(){ 
  meta: {extend: Animal},
  species: "gopher"
});

// Change storage property name back to default.
decl.dataKey = "decl-data";

Take a look at the unit tests for more examples.