npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

declare.js

v0.0.8

Published

OO system from node and browser

Downloads

345,252

Readme

Build Status

browser support

Declare is a library designed to allow writing object oriented code the same way in both the browser and node.js.

##Installation

npm install declare.js

Or download the source (minified)

###Requirejs

To use with requirejs place the declare source in the root scripts directory


define(["declare"], function(declare){
     return declare({
         instance : {
             hello : function(){
                 return "world";
             }
         }
     });
});

##Usage

declare.js provides

Class methods

  • as(module | object, name) : exports the object to module or the object with the name
  • mixin(mixin) : mixes in an object but does not inherit directly from the object. Note this does not return a new class but changes the original class.
  • extend(proto) : extend a class with the given properties. A shortcut to declare(Super, {});

Instance methods

  • _super(arguments): calls the super of the current method, you can pass in either the argments object or an array with arguments you want passed to super
  • _getSuper(): returns a this methods direct super.
  • _static : use to reference class properties and methods.
  • get(prop) : gets a property invoking the getter if it exists otherwise it just returns the named property on the object.
  • set(prop, val) : sets a property invoking the setter if it exists otherwise it just sets the named property on the object.

###Declaring a new Class

Creating a new class with declare is easy!


var Mammal = declare({
     //define your instance methods and properties
     instance : {

         //will be called whenever a new instance is created
         constructor: function(options) {
             options = options || {};
             this._super(arguments);
             this._type = options.type || "mammal";
         },

         speak : function() {
             return  "A mammal of type " + this._type + " sounds like";
         },

         //Define your getters
         getters : {

             //can be accessed by using the get method. (mammal.get("type"))
             type : function() {
                 return this._type;
             }
         },

          //Define your setters
         setters : {

               //can be accessed by using the set method. (mammal.set("type", "mammalType"))
             type : function(t) {
                 this._type = t;
             }
         }
     },

     //Define your static methods
     static : {

         //Mammal.soundOff(); //"Im a mammal!!"
         soundOff : function() {
             return "Im a mammal!!";
         }
     }
});

You can use Mammal just like you would any other class.

Mammal.soundOff("Im a mammal!!");

var myMammal = new Mammal({type : "mymammal"});
myMammal.speak(); // "A mammal of type mymammal sounds like"
myMammal.get("type"); //"mymammal"
myMammal.set("type", "mammal");
myMammal.get("type"); //"mammal"

###Extending a class

If you want to just extend a single class use the .extend method.


var Wolf = Mammal.extend({

  //define your instance method
  instance: {

       //You can override super constructors just be sure to call `_super`
      constructor: function(options) {
         options = options || {};
         this._super(arguments); //call our super constructor.
         this._sound = "growl";
         this._color = options.color || "grey";
     },

     //override Mammals `speak` method by appending our own data to it.
     speak : function() {
         return this._super(arguments) + " a " + this._sound;
     },

     //add new getters for sound and color
     getters : {

          //new Wolf().get("type")
          //notice color is read only as we did not define a setter
         color : function() {
             return this._color;
         },

         //new Wolf().get("sound")
         sound : function() {
             return this._sound;
         }
     },

     setters : {

         //new Wolf().set("sound", "howl")
         sound : function(s) {
             this._sound = s;
         }
     }

 },

 static : {

     //You can override super static methods also! And you can still use _super
     soundOff : function() {
         //You can even call super in your statics!!!
         //should return "I'm a mammal!! that growls"
         return this._super(arguments) + " that growls";
     }
 }
});

Wolf.soundOff(); //Im a mammal!! that growls

var myWolf = new Wolf();
myWolf instanceof Mammal //true
myWolf instanceof Wolf //true

You can also extend a class by using the declare method and just pass in the super class.

//Typical hierarchical inheritance
// Mammal->Wolf->Dog
var Dog = declare(Wolf, {
   instance: {
       constructor: function(options) {
           options = options || {};
           this._super(arguments);
           //override Wolfs initialization of sound to woof.
           this._sound = "woof";

       },

       speak : function() {
           //Should return "A mammal of type mammal sounds like a growl thats domesticated"
           return this._super(arguments) + " thats domesticated";
       }
   },

   static : {
       soundOff : function() {
           //should return "I'm a mammal!! that growls but now barks"
           return this._super(arguments) + " but now barks";
       }
   }
});

Dog.soundOff(); //Im a mammal!! that growls but now barks

var myDog = new Dog();
myDog instanceof Mammal //true
myDog instanceof Wolf //true
myDog instanceof Dog //true


//Notice you still get the extend method.

// Mammal->Wolf->Dog->Breed
var Breed = Dog.extend({
   instance: {

       //initialize outside of constructor
       _pitch : "high",

       constructor: function(options) {
           options = options || {};
           this._super(arguments);
           this.breed = options.breed || "lab";
       },

       speak : function() {
           //Should return "A mammal of type mammal sounds like a
           //growl thats domesticated with a high pitch!"
           return this._super(arguments) + " with a " + this._pitch + " pitch!";
       },

       getters : {
           pitch : function() {
               return this._pitch;
           }
       }
   },

   static : {
       soundOff : function() {
           //should return "I'M A MAMMAL!! THAT GROWLS BUT NOW BARKS!"
           return this._super(arguments).toUpperCase() + "!";
       }
   }
});


Breed.soundOff()//"IM A MAMMAL!! THAT GROWLS BUT NOW BARKS!"

var myBreed = new Breed({color : "gold", type : "lab"}),
myBreed instanceof Dog //true
myBreed instanceof Wolf //true
myBreed instanceof Mammal //true
myBreed.speak() //"A mammal of type lab sounds like a woof thats domesticated with a high pitch!"
myBreed.get("type") //"lab"
myBreed.get("color") //"gold"
myBreed.get("sound")" //"woof"

###Multiple Inheritance / Mixins

declare also allows the use of multiple super classes. This is useful if you have generic classes that provide functionality but shouldnt be used on their own.

Lets declare a mixin that allows us to watch for property changes.

//Notice that we set up the functions outside of declare because we can reuse them

function _set(prop, val) {
    //get the old value
    var oldVal = this.get(prop);
    //call super to actually set the property
    var ret = this._super(arguments);
    //call our handlers
    this.__callHandlers(prop, oldVal, val);
    return ret;
}

function _callHandlers(prop, oldVal, newVal) {
   //get our handlers for the property
    var handlers = this.__watchers[prop], l;
    //if the handlers exist and their length does not equal 0 then we call loop through them
    if (handlers && (l = handlers.length) !== 0) {
        for (var i = 0; i < l; i++) {
            //call the handler
            handlers[i].call(null, prop, oldVal, newVal);
        }
    }
}


//the watch function
function _watch(prop, handler) {
    if ("function" !== typeof handler) {
        //if its not a function then its an invalid handler
        throw new TypeError("Invalid handler.");
    }
    if (!this.__watchers[prop]) {
        //create the watchers if it doesnt exist
        this.__watchers[prop] = [handler];
    } else {
        //otherwise just add it to the handlers array
        this.__watchers[prop].push(handler);
    }
}

function _unwatch(prop, handler) {
    if ("function" !== typeof handler) {
        throw new TypeError("Invalid handler.");
    }
    var handlers = this.__watchers[prop], index;
    if (handlers && (index = handlers.indexOf(handler)) !== -1) {
       //remove the handler if it is found
        handlers.splice(index, 1);
    }
}

declare({
    instance:{
        constructor:function () {
            this._super(arguments);
            //set up our watchers
            this.__watchers = {};
        },

        //override the default set function so we can watch values
        "set":_set,
        //set up our callhandlers function
        __callHandlers:_callHandlers,
        //add the watch function
        watch:_watch,
        //add the unwatch function
        unwatch:_unwatch
    },

    "static":{

        init:function () {
            this._super(arguments);
            this.__watchers = {};
        },
        //override the default set function so we can watch values
        "set":_set,
        //set our callHandlers function
        __callHandlers:_callHandlers,
        //add the watch
        watch:_watch,
        //add the unwatch function
        unwatch:_unwatch
    }
})

Now lets use the mixin

var WatchDog = declare([Dog, WatchMixin]);

var watchDog = new WatchDog();
//create our handler
function watch(id, oldVal, newVal) {
    console.log("watchdog's %s was %s, now %s", id, oldVal, newVal);
}

//watch for property changes
watchDog.watch("type", watch);
watchDog.watch("color", watch);
watchDog.watch("sound", watch);

//now set the properties each handler will be called
watchDog.set("type", "newDog");
watchDog.set("color", "newColor");
watchDog.set("sound", "newSound");


//unwatch the property changes
watchDog.unwatch("type", watch);
watchDog.unwatch("color", watch);
watchDog.unwatch("sound", watch);

//no handlers will be called this time
watchDog.set("type", "newDog");
watchDog.set("color", "newColor");
watchDog.set("sound", "newSound");

###Accessing static methods and properties witin an instance.

To access static properties on an instance use the _static property which is a reference to your constructor.

For example if your in your constructor and you want to have configurable default values.

consturctor : function constructor(opts){
    this.opts = opts || {};
    this._type = opts.type || this._static.DEFAULT_TYPE;
}

###Creating a new instance of within an instance.

Often times you want to create a new instance of an object within an instance. If your subclassed however you cannot return a new instance of the parent class as it will not be the right sub class. declare provides a way around this by setting the _static property on each isntance of the class.

Lets add a reproduce method Mammal

reproduce : function(options){
    return new this._static(options);
}

Now in each subclass you can call reproduce and get the proper type.

var myDog = new Dog();
var myDogsChild = myDog.reproduce();

myDogsChild instanceof Dog; //true

###Using the as

declare also provides an as method which allows you to add your class to an object or if your using node.js you can pass in module and the class will be exported as the module.

var animals = {};

Mammal.as(animals, "Dog");
Wolf.as(animals, "Wolf");
Dog.as(animals, "Dog");
Breed.as(animals, "Breed");

var myDog = new animals.Dog();

Or in node

Mammal.as(exports, "Dog");
Wolf.as(exports, "Wolf");
Dog.as(exports, "Dog");
Breed.as(exports, "Breed");

To export a class as the module in node

Mammal.as(module);