您的位置:首页 > Web前端 > JavaScript

Javascript面向对象扩展库

2012-04-22 19:48 357 查看
最近一直在用js做项目,遇到了许多需要应用面向对象来设计的功能,由于js对OOP的原生支持还不是很完善,所以就写了一个面向对象的扩展库用做底层支持,现在把它单独整理出来,完善了一些功能,在这里分享一下。

lang.js库提供了包和类的定义、类的继承与混合(mixin)、函数重载等功能,基本可满足大多数面向对象设计的需求。同时支持基于链式的定义方式,让库在使用时更加规范和便捷。下面首先通过简单的例子演示了lang.js的基本功能,之后给出了lang.js的源码及注释。

一.功能介绍

“lang”作为框架的全局定义,其中包括了四个方法:

lang.Package(string name)
//用于定义包(默认会暴露到全局)

lang.Class(string name[, object config], object classBody)
//用于定义类

lang.Object(string name | object body)
//用于定义支持重载函数的普通对象

lang.Function(string name | object body)
//用于定义重载函数

//1.基本的包和类的定义:

//首先通过全局函数Package定义一个包,下面可通过链式调用向包中定义类、对象或函数。

Package('com.site').

Class('Base',{

Base: function(tagName){

this.element = document.createElement(tagName);

},

add: function(child){

this.element.appendChild(child);

},

show: function(){

alert('I am Base!');

}

}).

Class('Control', {

Control: function(){

//do soming

}

});

alert(com.site);

alert(com.site.Base);

alert(com.site.Control);

//2.普通对象定义

//一个不需初始化的类,可直接定义成普通对象

Package('com.site.util').

Object({

ModelA: {

say: function(){

alert('ModelA: Hello!');

}

},

ModelB: {

print: function(){

alert('ModelB: ' + this.Class.Type.name);

}

}

});

com.site.util.ModelA.say();

//3.类的继承

//像很多面向对象语言一样,这里约定一个类只能拥有一个父类。但是可以通过mixin混合多个普通对象。

//在子类的构造函数中可以通过this.base访问父类的构造函数。

//如子类定义了与父类相同函数,父类函数将被重写,这里同样可以通过this.base调用父类被重写的函数。

Package('com.site').

Class('Panel', {extend: com.site.Base, mixin:[com.site.util.ModelA, com.site.util.ModelB]}, {

Panel: function(tagName){

//这里使用this.base调用父类构造函数

this.base(tagName);

},

show: function(){

alert('I am Panel!');

this.base();

}

});

var panel = new com.site.Panel("div");

panel.say();

panel.print();

alert(panel.element.outerHTML);

//4.静态成员的定义

/*

程序中可以将类的主体以函数的形式定义,将私有成员定义在函数内部,将公共成员以返回值的形式暴露出来。这种设计模式在很多流行框架中都可以看到,虽然隐藏的成员只能是静态的,不过这也足以满足大部分的需求了。

公有的静态成员可以通过Static标签定义,Static中可包含一个静态构造函数,该函数只会在类第一次创建的时候执行一次。

在运行期间类的内部可以通过this.Class.xxx的形式访问自身的静态成员,(this.Class就是所属类的引用)

*/

Package('com.site').

Class('Button', {extend: com.site.Panel}, function(){

//在这里定义私有静态成员

var tagName = 'BUTTON';

var onclick = function(){

alert('I am a Button!');

}

return {

//这里定义共有静态成员

Static: {

count: 1,

//静态构造函数

Button: function(){

this.createTime = new Date();

}

},

Button: function(text){

this.base(tagName);

this.element.innerHTML = text;

this.element.onclick = onclick;

//调用静态变量

this.Class.count++;

}

};

});

var button = new com.site.Button("Button1");

document.body.appendChild(button.element);

alert(com.site.Button.count);

//5.重载函数的定义

/*

lang.js中对函数重载提供了较完善的支持,在定义函数时可在函数名后面指定参数签名,调用函数时程序根据传入的参数自动匹配转发。

其中支持的类型包括:var,string,number,boolean,array,date,object,function,element和自定义的类(var表示任意类型,element表示DOM元素。)

为了保证灵活性,重载支持通配符功能,遵循正则表达式的规则,可以通过标记“+ * ? {?,?}”来处理不确定参数个数的情况。

重载函数在类的继承过程中是有效的,签名不同的函数不会被重写,被重写的父类重载函数同样支持通过this.base调用。

以下代码为重载在类中应用的例子:

*/

Package('com.site').

Class('Student',{

Static: {

//静态函数重载

'create()': function(){

//这里的this就是类本身,所以可以直接new

return new this('静态', 1);

},

'create(string, number)': function(name, age){

return new this(name, age);

},

'search()': function(){

alert('search(*)');

},

'search(string)': function(name){

alert('search('+name+')');

}

},

//构造函数重载

'Student()': function(){

//利用this.self调用自身构造函数"Student(string, number)"

this.self('未知', 0);

},

'Student(string, number)': function(name, age){

this.name = name;

this.age = age;

},

//普通成员函数重载

'print()': function(){

this.print(this.name ,this.age);

},

'print(string, number)': function(name, age){

alert('name:' + name + ',age:' + age);

},

//支持自定义类的类型

'print(lib.ui.Panel)': function(panel){

this.print(panel, true);

},

'print(lib.ui.Panel, boolean)': function(panel, append){

if(append){

panel.element.innerHTML += this.name;

}else{

panel.element.innerHTML = this.name;

}

}

}).

//继承中对重载的支持

Class('MaleStudent',{extend: com.site.Student},{

Static: {

//重写父类静态函数

'search(string)': function(name){

alert('MaleStudent: search('+name+')');

},

'search(string, number)': function(name, age){

alert('MaleStudent: search('+name+','+age+')');

}

},

'MaleStudent': function(){

//调用父类的构造函数"Student(string, number)"

this.base('未知男同学', 0);

},

'MaleStudent(string, number)': function(name, age){

//调用父类的构造函数"Student(string, number)"

this.base(name, age);

},

//重写了父类的重载函数

'print()': function(){

alert('MaleStudent: name:' + this.name + ',age:' + this.age);

},

'print(string, number)': function(name, age){

//通过this.base调用父类函数"print(string, number)"

this.base('<'+name+'>', '<' + age + '>');

},

//模糊匹配,这个函数可接受一个或多个字符串和零个或多个数字

'print(string+, number*)': function(){

var msg = [];

for(var i=0; i<arguments.length; i++){

msg.push(arguments[i]);

}

alert('print(string+, number*):' + msg.join('+'));

}

});

//创建对象时会自动判断调用的构造函数

var studentA = new com.site.Student();

studentA.print();

var studentB = new com.site.MaleStudent('王小虎', 19);

studentB.print();

studentB.print('小虎', 19);

//这里调用了模糊匹配的重载函数

studentB.print('a','b','c');

studentB.print('x','y','z', 1, 2 ,3);

var studentC = new com.site.MaleStudent();

studentC.print();

//调用静态重载函数

var student = com.site.Student.create();

student.print();

com.site.Student.search();

com.site.Student.search('某同学');

//共有的静态函数会继承到子类,所以MaleStudent也可以create

var maleStudent = com.site.MaleStudent.create('小红', 18);

maleStudent.print();

com.site.MaleStudent.search('小明');

com.site.MaleStudent.search('小明',20);

//6.匿名定义

//有些时候,我们不希望显示的指定一个类或函数的名字,只希望把它保存到变量里面,那么可以通过匿名的方式进行定义。

//1)使用lang.Class创建匿名类

var clazz = lang.Class({

//匿名类的名字统一为Anonymous,所以构造函数的名字也要是Anonymous

Anonymous: function(name){

this.name = name;

},

show: function(){

alert(this.name);

}

});

alert(clazz);

new clazz('匿名类').show();

//2)使用lang.Function创建匿名重载函数

var fn = lang.Function({

'(default)': function(){

var a = [].slice.call(arguments, 0);

alert(a);

},

'(string)': function(a){

alert('(string): ' + a);

},

'(string, number)': function(a, b){

alert('(string, number): ' + a + ':' + b);

},

'(number)': function(a){

alert('(number): ' + a);

}

});

alert(fn);

fn('message');

fn('message', 1);

fn(1);

fn(1,2,3,4,5);

//3)使用lang.Object创建支持重载函数的普通对象

var obj = lang.Object({

name: 'jim',

'write()': function(){

this.write(this.name);

},

'write(string)': function(name){

alert(name);

}

});

obj.write();

obj.write('joe');

//7.综合例子

Package("com.site").

Class('ClassA', {

print: function(){

alert(this.toString());

}

}).

Class('ClassB', {

print: function(){

alert(this.toString());

}

}).

Object({

fn1: function(){

alert(1);

},

fn2: function(){

alert(2);

},

'debug(string)': function(msg){

alert(msg);

},

'debug(string, number)': function(msg, num){

alert(num + ': ' + msg);

},

'debug(com.site.ClassA, string)': function(c, method){

alert('debug ClassA');

c[method]();

},

'debug(com.site.ClassB, string)': function(c, method){

alert('debug ClassB');

c[method]();

},

'debug(element)': function(element){

alert('element:' + element.outerHTML);

}

}).

Object('Web', {

'reload': function(){

alert('reload...');

},

'reload(function)': function(fn){

fn();

}

}).

Package('com.site.util').

Function('myfn(string)', function(name){

alert(name);

}).

Function('myfn(number)', function(num){

alert(num*num);

}).

Class('ClassA', {

ClassA: function(){

alert('ClassA!');

}

});

var div = document.createElement("div");

var span = document.createElement("span");

div.appendChild(span);

com.site.fn1();

com.site.fn2();

com.site.debug('info');

com.site.debug('info', 1);

com.site.debug(new com.site.ClassA(), 'print');

com.site.debug(new com.site.ClassB(), 'print');

com.site.debug(div);

com.site.Web.reload();

com.site.Web.reload(function(){alert('callback');});

com.site.util.myfn('Jim');

com.site.util.myfn(100);

new com.site.util.ClassA();

//8.自描述信息

/*

自描述就是类或对象在定义完成后对自身的信息的描述,常常用于实现一些特殊的功能,库中通过Type"保留字"存储类或包的自描述信息。

下面为使用方法:

*/

var value = com.site.Student;

alert('判断是否一个类:' + (value.Type && value.Type.type == 'class'));

alert('取完整类名:' + com.site.Student.Type.name);

alert('取父类完整类名:' + com.site.MaleStudent.Type.baseClass.Type.name);

alert('取短类名:' + com.site.Student.Type.shortName);

alert('取一个类的包名:' + com.site.Student.Type.Package.Type.name);

复制代码

二.源码详解

var lang = (function(){

/***********************************

Javascript面向对象扩展库(lang.js v1.0)

By: X!ao_f

QQ: 120000512

Mail: xiao_f.mail#163.com

************************************/

var customToString = function(){

return '[' + this.Type.type + ' ' + this.Type.name + ']';

}

//支持重载的方法定义

var createMethod = (function(){

//创建一个代理函数

var createMethodProxy = function(context, name){

//当调用重载的函数时,首先会执行该函数分析传入的参数,进行匹配和转发

var method = function(){

//在第一次调用时初始化,将映射信息缓存

if(!method.__initialized__){

initializeMethod(method);

}

//将参数类型拼接成函数签名

var signature;

if(arguments.length){

var list = [];

for(var i=0; i<arguments.length; i++){

var typename;

var argument = arguments[i];

if(argument === undefined || argument === null){

typename = 'object';

}else if(argument instanceof Array){

typename = 'array';

}else if(argument instanceof Date){

typename = 'date';

}else{

typename = typeof argument;

if(typename == 'object'){

if('Class' in argument){

typename = argument.Class.Type.name;

}else if('nodeType' in argument){

typename = 'element';

}

}

}

list.push(typename);

}

signature = list.join(',');

}else{

signature = '';

}

//如果常规缓存中存在匹配的签名,直接调用

if(method.__overloads__[signature]){

return method.__overloads__[signature].apply(this, arguments);

}else{

//缓存中不存在时,尝试利用正则进行模糊匹配

//首先判断模糊匹配缓存中是否存在记录,如存在直接调用

if(method.__overloadsCache__[signature]){

return method.__overloadsCache__[signature].apply(this, arguments);

}

//循环匹配

for(var i=0; i<method.__overloadsRegExp__.length; i++){

//如果匹配成功,将映射关系存入模糊匹配缓存,同时调用并返回

if(method.__overloadsRegExp__[i].regexp.test(signature)){

method.__overloadsCache__[signature] = method.__overloadsRegExp__[i].fn;

return method.__overloadsRegExp__[i].fn.apply(this, arguments);

}

}

//如果依然无法找到对应的函数,判断是否存在默认函数

if(method.__overloads__['default']){

return method.__overloads__['default'].apply(this, arguments);

}else if(method.__overloads__['']){

return method.__overloads__[''].apply(this, arguments);

}else{

alert('Error: '+method.Type.name+'('+signature+') is undefined.');

}

}

};

//内置对象

method.__context__ = context;

method.__functions__ = {};

method.toString = customToString;

//自描述信息

method.Type = {

name: name,

Method: method,

type: 'method'

};

return method;

}

//初始化

var initializeMethod = function(method){

//基础签名缓存

method.__overloads__ = {};

//模糊匹配正则缓存

method.__overloadsRegExp__ = [];

//模糊匹配结果缓存

method.__overloadsCache__ = {};

//例举所有定义的函数

for(var signature in method.__functions__){

var fn = method.__functions__[signature];

var params = signature.substring(signature.indexOf('(') + 1, signature.length - 1);

var pure = !/[\*\+\?\{]/.test(params);

//如果不存在通配符直接保存到基础签名缓存

if(pure){

method.__overloads__[params] = fn;

}else{

//生成模糊匹配正则

var regexp = '^' + params

.replace(/([\w\.]+)(\{.*?\})?/g, '($1(,|$))$2')

.replace(/\./g, '\\.')

.replace(/((\()var(\())/g, '$2\\w+$3')

.replace(/,\(/g, '(') + '$';

method.__overloadsRegExp__.push({ regexp: new RegExp(regexp), fn: fn });

}

}

method.__initialized__ = true;

}

//返回外部的定义函数

return function(signature, fn, comp){

//如果传入的为一个对象,视为定义匿名方法

if(typeof signature == 'object'){

var context = {};

var method;

for(var key in signature){

method = createMethod.call(context, 'anonymous'+key, signature[key]);

}

return method;

}

signature = signature.replace(/\s+/g, '');

var index = signature.indexOf('(');

var name = index > -1 ? signature.substring(0, signature.indexOf('(')) : signature;

var context = this;

var method = context[name];

//上下文中不存在函数定义,视为第一次定义

if(method === undefined){

context[name] = method = createMethodProxy(context, name);

}else if(!method.Type || method.Type.type!='method'){

//上下文存在的函数是原生函数,将这个函数作为默认函数存入列表

var temp = method;

context[name] = method = createMethodProxy(context, name);

method.__functions__[name + '()'] = temp;

}else{

//如果上下文不同,创建新的重载方法并将已经存在的函数复制,这里主要解决类继承中子类与父类冲突的问题

//如果上下文相同,直接将初始化标记设为false,待下次调用时重新初始化

if(method.__context__ !== context){

var temp = method;

context[name] = method = createMethodProxy(context);

for(var sign in temp.__functions__){

method.__functions__[sign] = temp.__functions__[sign];

}

}else{

method.__initialized__ = false;

}

}

//将本次定义的函数添加到函数列表

//先入为主策略

if(comp){

if(fn.__functions__){

for(var key in fn.__functions__){

if(key in method.__functions__){

method.__functions__[key].__overridden__ = fn;

}else{

method.__functions__[key] = fn;

}

}

}else{

if(signature in method.__functions__){

method.__functions__[signature].__overridden__ = fn;

}else{

method.__functions__[signature] = fn;

}

}

}else{

//后入为主策略

if(fn.__functions__){

for(var key in fn.__functions__){

if(key in method.__functions__){

fn.__functions__[key].__overridden__ = method;

}

method.__functions__[key] = fn.__functions__[key];

}

}else{

if(signature in method.__functions__){

fn.__overridden__ = method;

}

method.__functions__[signature] = fn;

}

}

if(this.Type && this.Type.type == 'package'){

return this;

}else{

return method;

}

};

})();

//类定义函数

var createClass = (function(){

var slice = Array.prototype.slice;

var emptyFn = function(){};

var createClass = function(name){

return function(){

this[name].apply(this, slice.call(arguments, 0));

};

}

//用于调用被重写函数

var baseCaller = function(){

if(arguments.length){

var args = slice.call(arguments, 0);

return baseCaller.caller.__overridden__.apply(this, args);

}else{

return baseCaller.caller.__overridden__.call(this);

}

}

//用于调用自身重载构造函数

var selfCaller = function(){

if(arguments.length){

var args = slice.call(arguments, 0);

return selfCaller.caller.__self__.apply(this, args);

}else{

return selfCaller.caller.__self__.call(this);

}

}

var filter = {prototype:true, Type:true};

//快速浅拷贝

function clone(a){

var fn = function(){};

fn.prototype = a;

return new fn;

}

//对象复制,替换存在的(后入为主)

function replace(base, self){

for(var key in self){

if(!(key in filter)){

if(typeof self[key] == 'function'){

//如果子类函数包含重载签名或父类函数已经重载

if(key.indexOf('(') > -1 || (base[key] && base[key].__functions__)){

createMethod.call(base, key, self[key]);

}else{

//常规函数定义

if(key in base){

//记录重写信息

self[key].__overridden__ = base[key];

}

base[key] = self[key];

}

}else{

base[key] = self[key];

}

}

}

}

//对象复制,只取补集(先入为主)

function complement(self, base){

for(var key in base){

if(!(key in filter)){

if(typeof base[key] == 'function'){

if(key.indexOf('(') > -1 || (self[key] && self[key].__functions__)){

createMethod.call(self, key, base[key], true);

}else{

if(key in self){

//记录重写信息

self[key].__overridden__ = base[key];

}else{

self[key] = base[key];

}

}

}else if(!(key in self)){

self[key] = base[key];

}

}

}

}

return function(){

//处理参数

if(this.Type && this.Type.type == 'package'){

if(arguments.length == 2){

var name = arguments[0];

var body = arguments[1];

}else{

var name = arguments[0];

var config = arguments[1];

var body = arguments[2];

}

}else{

if(arguments.length == 1){

var name = 'Anonymous';

var body = arguments[0];

}else{

var name = 'Anonymous';

var config = arguments[0];

var body = arguments[1];

}

}

//创建类的基础函数

var clazz = createClass(name);

//获取父类信息

var baseClass;

if(config && config.extend){

baseClass = config.extend;

}

//如果传入的主体为函数,取其返回值

if(typeof body == 'function'){

body = body(clazz);

}

//处理静态成员

if(body.Static){

complement(clazz, body.Static);

delete body.Static;

body = body.Public||body;

}else{

body = body.Public||body;

}

//处理继承

if(baseClass){

//通过快速浅拷贝复制父类成员

clazz.prototype = clone(baseClass.prototype);

//继承静态成员

complement(clazz, baseClass);

//继承类成员

complement(clazz.prototype, body);

}else{

//不存在继承

clazz.prototype = {};

complement(clazz.prototype, body);

}

//处理混合

if(config && config.mixin){

var mixin = config.mixin;

if(mixin instanceof Array){

for(var i=0; i<mixin.length; i++){

replace(clazz.prototype, mixin[i]);

}

}else{

replace(clazz.prototype, mixin);

}

}

//添加内置函数

clazz.prototype.base = baseCaller;

clazz.prototype.self = selfCaller;

clazz.prototype.constructor = clazz;

clazz.prototype.toString = customToString;

clazz.toString = customToString;

clazz.prototype.Class = clazz;

if(clazz.prototype[name]){

var constructor = clazz.prototype[name];

if(constructor.__functions__){

for(var key in constructor.__functions__){

//存在重载时,添加自身引用,用于通过this.self调用重载构造函数

constructor.__functions__[key].__self__ = constructor;

//存在继承时,将父类的构造函数作为被重写的函数,配置给当前类的构造函数

//用于通过base调用父类构造函数

if(baseClass){

constructor.__functions__[key].__overridden__ = baseClass.prototype[baseClass.Type.shortName];

}

}

}else if(baseClass){

clazz.prototype[name].__overridden__ = baseClass.prototype[baseClass.Type.shortName];

}

}else{

clazz.prototype[name] = emptyFn;

}

//类型自描述信息

//如果当前上下文是一个包,将类添加到包中

if(this.Type && this.Type.type == 'package'){

clazz.Type = {

type:'class',

name: this.Type.name+'.'+name,

shortName: name,

Package: this,

Class: clazz,

baseClass: baseClass

}

clazz.prototype.Type = {

type: 'object',

name: this.Type.name+'.'+name

}

//将类添加到包

this[name] = clazz;

//调用静态构造函数

if(name in clazz){

clazz[name].call(clazz);

}

//返回this用于链式调用

return this;

}else{

//上下文不是包则直接返回

clazz.Type = {

type:'class',

name: name,

shortName: name,

Class: clazz,

baseClass: baseClass

}

clazz.prototype.Type = {

type: 'object',

name: name,

baseClass: baseClass

}

if(name in clazz){

clazz[name].call(clazz);

}

return clazz;

}

};

})();

//用于创建支持重载的普通对象

var createObject = function(objects, config){

var target;

if(this.Type && this.Type.type == 'package'){

target = this;

}else{

target = {};

}

if(typeof objects == 'string'){

target = this[objects] = {};

objects = config;

}else if(typeof objects == 'function'){

objects = objects();

}

for(var key in objects){

if(typeof objects[key] == 'function' && (key.indexOf('(') > -1 || typeof target[key] == 'function')){

createMethod.call(target, key, objects[key]);

}else{

target[key] = objects[key];

}

}

if(this.Type && this.Type.type == 'package'){

return this;

}else{

return target;

}

};

//用于创建包

var createPackage = (function(){

var root = this;

return function(package){

var name = [];

var path = package.split('.');

var parent = root;

for(var i=0; i<path.length; i++){

name.push(path[i]);

if(parent[path[i]]){

parent = parent[path[i]];

}else{

var pack = {

Class: createClass,

Object: createObject,

Function: createMethod,

Package: createPackage,

toString: customToString

};

pack.Type = {

type: 'package',

Package: pack,

name: name.join('.')

}

parent = parent[path[i]] = pack;

}

}

return parent;

}

})();

//默认将Package暴露

window.Package = createPackage;

return {

Package: createPackage,

Class: createClass,

Function: createMethod,

Object: createObject

};

})();

复制代码

结束语:

到这里,lang.js的应用和原理就介绍完毕了,该库在主流浏览器中均已测试通过,

如果想使用lang.js,可以在这里免费下载,如发现什么问题,或有好的建议可以反馈给我。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: