Giter Site home page Giter Site logo

joo's Introduction

Simple class declaration function to write OO code in JavaScript

This library provides a simple class declaration function. Classes defined with this function behave exactly as same as normal JavaScript constructor functions. This program aims to be as just a syntax sugar to easily declare Classes, its inheritance, Mix-ins, namespace, statics etc. without any dependencies on other libraries nor any conflicts with them.

Table of contents

in Node.js

install joo with npm npm install joo, then require it as below.

var def = require('joo');

in HTML

load joo as a script <script type="text/javascript" src="/path/to/joo.js"></script>, then require it as below.

var def = require_joo();

Then, define your class with def().

function MyClass() {}
def(MyClass).
it.provides({
    doSomething: function() {}
});

Here is the whole API of this program.

var def = require_joo();

def(function() {
    // This is the class constructor.
    // You can call SuperClass's constructor as below.
    this._super();
}).as('myapp.module.MyClass').
it.inherits(SuperClass).
it.borrows(MethodProvider, OtherProvider, AndMore).
it.hasStatic({
    STATIC_PROPERTY: [],
    STATIC_METHOD: function() {}
}).
it.provides({
    method: function() {
        // invocation of a method of the same name in SuperClass's implementation
        this._super();

        // below expressions refer the same static object.
        this._static.STATIC_PROPERTY;
        this.constructor.STATIC_PROPERTY;
        myapp.module.MyClass.STATIC_PROPERTY;
    }
});

The API provides .it as a syntactic ornament which makes class declaration look like natural sentences. Someone would claim that it causes unnecessary object reference, which influences performance. But I think it's acceptable cost unless you declare classes thouthands of times. Nevertheless, if you hate it, you can omit it.

def(MyClass).inherits(SuperClass).provides({...});

Now, let's take a look at each functionalities in detail.

First of all, you need to call require_joo(), which returns a function. To use the function, store it in any variable as you like, such as def, define, declare etc.

var def = require_joo();

// You can define constructor function in a standard way.
function BaseClass(name) {
    this.name = name;
}

// Then, you can define methods by chaining '.it.provides()' method.
def(BaseClass).it.provides({
    getName: function() {
        return this.name;
    }
});

That's it. You can use the class exactly as same as a standard JavaScript class.

var base = new BaseClass('base');

base instanceof BaseClass      // true
base.constructor === BaseClass // true
base.getName();                // 'base'

You can define class inheritance as below:

function ChildClass(name, age) {
    // You can call super class' constructor by 'this._super()'.
    this._super(name);
    this.age = age;
}
def(ChildClass).
it.inherits(BaseClass).
it.provides({
    getAge: function() {
        return this.age;
    }
});

The most exciting thing is that the scope chain of this._super() woks perfectly even in multiple level inheritances. This is difficult to write in a standard way.

function GrandChildClass(name, age) {
    this._super(name, age);
}
def(GrandChildClass).
it.inherits(ChildClass).
it.provides({
    getName: function() {
        // Even if the closest ancestor (in this case, ChildClass) doesn't implement getName() method explicitly,
        // this._super() method looks up to BaseClass's getName() method.
        // This is awesome, isn't it?
        return 'My name is ' + this._super();
    },
    getAge: function() {
        return 'I am ' + this._super();
    },
    toString: function() {
        // You can override built-in 'toString()' method in the same way.
        return this._super() + '(name: ' + this.name + ')'
    }
});

This works perfectly as we expect.

var g = new GrandChildClass('Hiroshi', 29);
g instanceof BaseClass;            // true
g instanceof ChildClass;           // true
g instanceof GrandChildClass;      // true
g.constructor == GrandChildClass;  // true
g.getName(); // 'My name is Hiroshi'
g.getAge();  // 'I am 29'
g + ''       // '[object Object](name: Hiroshi)'

Our class can borrow methods from other classes or objects through .borrows() method.

// Mix-in provider can be an object;
var MethodProvider = {
    methodA: function() {}
};
// or Classes.
function OtherProvider() {}
OtherProvider.prototype.methodB = function() {};

// Our class can borrow methods from these providers.
function OurClass() {}
def(OurClass).
it.borrows(MethodProvider, OtherProvider).
it.provides({
    ownMethod: function() {}
});

Now OurClass has methodA, methodB, ownMethod, but an instance of the class won't be a Mix-in provider's instance.

var c = new OurClass();
c instanceof MethodProvider; // false
c instanceof OtherProvider;  // false
c.methodA();
c.methodB();
c.ownMethod();

Here is an example of static properties.

function MyClass() {}
def(MyClass).it.hasStatic({
    FOO: 0,
    BAR: 1,
    BLAH: {
        BAZ: true
    }
}).provides({
    method: function() {
        // You can refer to static properties through ._static property in an instance method.
        this._static.FOO == MyClass.FOO; // true
    }
});

MyClass.FOO      // 0
MyClass.BAR      // 1
MyClass.BLAH.BAZ // true

It's good habitat to declare your classes in your module scope, then export it to global scope under your namespace; To achieve this, use .as() method.

(function() {
    var def = require_joo();

    function ModuleLocalClass() {}
    def(ModuleLocalClass).as('myapp.module.foo.bar.Blah').
    it.provides({/*...*/});
})();

new ModuleLocalClass() // reference error.
var blah = new myapp.module.foo.bar.Blah();
blah.constructor // ModuleLocalClass

If you pass a second argument as a context object to .as() method, classes are exported under the context instead of a global scope.

(function() {
    var def = require_joo();
    var context = {};
    def(function() {}).as('myapp.module.Class', context);
    new context.myapp.module.Class();
})();

Some parts of the code, especially .this._super() method implementation was inspired by John Resig's Simple JavaScript Inheritance, but I further improved several points.

In this library,

  • init method are not mandatory.

John Resig's implementation and many other libraries which provides original class system often requires us to declare init method as a constructor function. It is indeed convensional, but not standard. I wanted a simple syntax to use normal function as a class constructor. This is the main reason I wrote this code.

  • you can easily implement Mix-in class with .borrow() method.
  • this._super() method works appropriately both in constructors and in methods, even under multiple level inheritance.
  • .constructor property correctly points to its constructor.
  • declaration sentences look like a natural language, and has explicit semantics.

I hope this simple library would be useful to other developers.

define(MyClass).as('myapp.module.MyClass').
it.inherits(SuperClass).
it.borrows(Provider, OtherProvider).
it.provides({
    ownMethod: function() {
    }
});

joo's People

Contributors

kuwabarahiroshi avatar nazomikan avatar sandbox-app avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.