adm-jclass: 一个面向对象编程的js库

https://code.google.com/p/adm-jclass/:
A javascript library that allows highly object-oriented application programming in your browser.

介绍: https://code.google.com/p/adm-jclass/wiki/jClassDocumentation
jClass is a Java Script library that allows you to write highly object-oriented code.

Introduction
jClass is a JavaScript a javascript library that allows highly object-oriented application programming in your browser.

jClass
jClass is the base Object all classes extend from and can inherit other jClass Objects and/or implement JInterface objects.

The base jClass Object contains the following properties/methods

Name Type/Return Type Description
_prototype Object, An object describing the class
_prototype.typeName String, Name of the current class type
_prototype.instanceId Number, Unique class identifier
_prototype.implementing Array, An array of interface ID's the class is implementing
_prototype.extending Array, An array of class ID's the class is inheriting from
isImplementationOf(jInterface) Boolean Returns true if the class is implementing the given jInterface object
isInstanceOf(jClass) Boolean, Returns true if the class is inheriting from the given jClass object
Thing to consider: When you create a jClass that both extends another class and implements an interface, the order must be

var MyClass = jClass.extend(MyBaseClass).implement(MyInterface)({ .... })

When you extend a class, the subclass inherits all of the public members from the parent class. Unless a class overrides those methods, they will retain their original functionality.

var BaseClass = jClass({
    public : {
       add : function(x,y) {
          total = x + y;
          return total;
       },
       total : 0
    }
})

var MyClass = jClass.extend(BaseClass)({
    public : {
       add : function(x,y) {   // overiding a parent function
           _super.add(x,y);    // _super.add refers to the class defined in the parent
           return this.total;  // total is available by inheritance 
       }
    }
})



jInterface
Object interfaces allow you to create code which specifies which methods a class must implement, without having to define how these methods are handled. Defining a body for the methods here will throw an error.

All methods declared in an interface must be public, this is the nature of an interface.

You can also declare properties in the interface and not only functions

// defining interface

var IMyInterface = jInterface({
    someFunction : function() {},
    someOtherFunction : function(param1, param2) {},

    name : "",
    someId : 0
});

// implementing interface

var MyClass = jClass.implement(IMyInterface)({
   public : {
      someFunction : function() {
         // method body
      },
      someOtherFunction : function(param1, param2) {
         // method body
      },

      name : "Hello World!",
      someId : Math.rand()
   }
})



Keywords and Access Modifiers
A jClass object can have 4 base blocks interpreted by the jClass compiler.

constructor (function) - a function that will be called when the class is instantiated (can be overloaded)
public (object) - public properties and methods available outside the class.
private (object) - private properties and methods available only inside the class.
static (object) - static properties and methods available without instantiating the class
  var MyClass = jClass({
     constructor : function(arguments, ...) {
        // ....
     },
     public : { 
        im_static_too : Static(function() { .... }),
        // ....
     },
     private : {
        // ....
     },
     static : {
        // ....
     },
     SomeFunction : function() { ... },
     SomeObject : { ... },
     SomeProperty  : "..."
  })

Defining anything outside these blocks (constructor, public, private, static) is automatically moved in the public block.

You can also define a static member by wrapping it in Static() (like in the example above, im_static_too() becomes static).

If you wish to define more function with different number of parameters but they all must have the same name, you can use the Overload() function.

   find : Overload(function(name) { ... }, function(name, age) { ... })

   ....
 
   obj.find('john'); // calls the first function and finds by name
   obj.find('john', 20); // calls the second function and finds by name and age



Setters and Getters
If you wish to define a property but call a function whenever that value is changed or read, you can define it using GetSet(), Get(), Set() and it will behave just like any other variable except your functions will be responsible of the actual value being written or read.

   tmp : GetSet(
          function() { // first method is the getter and should return the value
             // do someting before returning the value
             return _tmp;
          },
          function(val) { // second method is the setter and must set the value
             // do someting (validations, notifications, etc) with the value being set
             _tmp = val;
          }),
   count : Get(function() { // defining only a setter
              return _count;
           }),
   total : Set(function(val) { // defining only a setter
              _total = _total + val;
           })
   ....
  


  x.tmp = 2; // calls the setter with parameter 2
  x.tmp;     // calls the getter 

  x.count;      // calls the getter
  x.count = 3;  // no setter defined, this is Read-Only and will throw an error

  x.total = 10; // calls the setter
  x.total;      // no getter defined, this will return undefined


When you create a property and you make it a getter or a setter (or both), a private variable is automatically created and the name of that property will be the name you give it preceded by an underscore

   myvar : Get(function() {
           return _myvar; // _myvar is created by the compiler as a private variable
        });


Getters and Setters are defined using defineSetter prototype method available inside objects. Unfortunately, IE does not provide such a functionality and getters and setters are not available as described above. Until I find a method to make this work, getters and setters are available in IE as such:

   total : GetSet(function() { return _total; }, function(val) { _total = val; });

   obj.getTotal();  // calls getter
   obj.setTotal(1); // calls setter 



Other core functions
namespace(object)
In general, a namespace is an abstract container providing context for the items, in JavaScript, a namespace is an object, containing all the methods and objects you define inside without worrying that you may override others with same name

  namespace("my.namespace")({
       myFunction : function() { return 1; };
  });


  namespace("other.namespace")({
       myFunction : function() { return 2; };
  });

  my.namespace.myFucntion(); // 1
  other.namespace.myFunction(); // 2


include(file or namespace, ....)
jClass built in include/require functions allow you to load external files and/or libraries at runtime.

   include("some/jsfile.js", "some.name.space", ....);

Including namespaces you are required to respect a naming convention for your files and the place they are stored.

For example, if you create the namespace " my.namespace" and wish to include the namespace by name, the file name must be " namespace.js" and be located in " /libraries/my/namespace.js"

That " /libraries/" there is the folder where the libraries are located and has the default value of "/libraries/". If you wish to change this you can use another built in iniset function and change the LIB setting to wherever your libraries are lcoated

   iniset("LIB", "/path/to/js/libraries/");
   console.log(initget("LIB")); // "/path/to/js/libraries/"

   include("my.namespace"); // will load /path/to/js/libraries/my/namespace.js

Note! - The libraries 'repository' is only prepended when you include namespaces. It will not affect the path of a included file (Ex include("path/file.js"); will load path/file.js)

initset(name, value)
iniset() allows you to change some configuration variables that jClass uses internally. You can of course edit the jClass.js by hand but if you wish to use the minified version you may brake something.

A usage example can be seen above.

initget(name)
iniget() retrieves the current value of a jClass setting
 
console.log(iniget("LIB")); // returns "/libraries"/



IE
A boolean value indicating if user browser is Internet Explorer




You can use jClass to:

Define namespaces
Create and extend other classes
Create and implement interfaces
Define public/private/static/override/overload methods
Define getter and setter methods
The basic syntax for jClass is:

include("some.other.files");

namespace("my.namespace")
({
    MyClass : jClass.extends(BaseClass).implements(SomeInterf, SomeOtherInterf) 
    ({
        constructor : function(){ 
         .... 
        },
        private : {
          ....
        },
        public : {
          ....
        },
        static : {
          ....
        }
    }),
    OtherClass : jClass({
       ......
    })
})

A set of really useful libraries are also included. You can check them out in the Wiki

And a demonstration example:

File : libraries/adm/classes.js

namespace("adm.classes")
({
     // Defining a interface. Implement bodies for the methods here will throw an error
    ITestInterface = jInterface({
        add : function(name) {}
        remove : function() {}
    }),

    // Defining a class to extend later
    BaseClass = jClass({
        public : {
            add : function(name) {
                users.push(name);
            } 
            getUsers: function() {
                // returns reference to private variable users
                return users; 
            }
        },
        private : {
            // private variable, no one except this class can access this
            users : ['John', 'Bill']
        },
        static : {
            BASE_CLASS_STATIC : "i'm from base class"
        }
    })
});

File : index.html

include("adm.classes");

var MainClass = jClass.extend(adm.classes.BaseClass).implement(adm.classes.ITestInterface)({
     constructor : function() {
           // class constructed
           localCopy = _super.getUsers();
     },
     public : {
         // Not implementing this will throw and error because it's required by the interface
         remove : Overload(
                     function(name) { // delete user by name  
                         delete localCopy[localCopy.indexOf[name]];
                     },
                     // overloading function remove to delete users between start and end positions
                     function(start, end) {
                         localCopy.splice(start, end);
                     }
                  ),
          // Overiding baseclass function add()
          add : function(name) {
              _super.add(name);
              this.doSometing();
          },
          doDomething : function() {
               // does something
          },
          total : GetSet(function() {
                    return _total; // set total
                  },
                  function(val) {
                     _total = val; // get total 
                     this.doSomething();
                  })
     }, 
     private : {
        localCopy : []
     },
     static : {
        SOMETHING_STATIC : 123
     }
});

var obj = new MainClass();

obj.isInstanceOf(adm.classes.MainClass); // true
obj.isInstanceOf(BaseClass); // true
obj.isImplmentationOf(adm.classes.ITestInterface); // true

MainClass.SOMETHING_STATIC; // 123
MainClass.BASE_CLASS_STATIC; // inherited from base class "i'm from base class"

obj.total = 1; // calling setter: set's new value to _total and calls doSomething()
obj.total; // calling getter: returns value of _total (1)

obj.add('Tom'); // adds user Tom

obj.remove('Bill'); // removes user by name
obj.remove(0, 3); // removes users between 0-3

你可能感兴趣的:(Class)