javascript是个入门门槛很低的语言,甚至一个从来没有接触过javascript的技术人员,几小时内就可以写出一个简单有用的程序代码。

但是如果因此你就下结论:javascript是门简单的语言。那你就大错特错了。想写出高性能的代码,同样需要具备一个高级程序员的基本素养。

一个java或者c++程序员,不一定能写出高性能的javascript代码,但更容易写出高性能的javascript代码。

javascript的简单是基于它“胸襟广阔”的包容性。它声明时,不需要指定类型,甚至可以任意的转换类型。它面向对象,却没有类(Class)的限制。它是一门崇尚自由又非常严谨的语言,如果你是一个自由主义者,那么,拥抱javascript吧!

面向对象编程 (OOP) 是一种流行的编程方法。但javascript的OOP,较之JAVA、c++有很大的同,主要体现它的继承方式不同。javascript是基于原型PROTOTYPE继承的。所有对象都是基于原型链,最终追述到Object对象。

这里不想讨论过多的关于javascript的继承方式和其它语言的继承方式的不同之处。主要讨论如何封装javascript的Class,以便更好的管理和维护基础代码,减少重复代码,以及更好的模块化编程。

下面是几个github上找到的比较好的Class封装类库:

  一、MY-CLASS 

项目地址:https://github.com/jiem/my-class

先看基本用法:

a、新建一个类

(function() {// 新建类var Person = my.Class({// 添加静态方法
    STATIC: {AGE_OF_MAJORITY: 18},// 构造函数constructor: function(name, age) {this.name = name;this.age = age;},// 实例方法sayHello: function() {console.log('Hello from ' + this.name + '!');},// 实例方法drinkAlcohol: function() {this.age < Person.AGE_OF_MAJORITY ?console.log('Too young! Drink milk instead!') :console.log('Whiskey or beer?');}});// 暴露给命名空间myLib.Person = Person;})();var john = new myLib.Person('John', 16);
john.sayHello(); //log "Hello from John!"
john.drinkAlcohol(); //log "Too young! Drink milk instead!"

b、继承一个类

(function() {//Dreamer 继承 Personvar Dreamer = my.Class(Person, {// 构造方法constructor: function(name, age, dream) {Dreamer.Super.call(this, name, age);this.dream = dream;},// 实例方法sayHello: function() {superSayHello.call(this);console.log('I dream of ' + this.dream + '!');},// 实例方法wakeUp: function() {console.log('Wake up!');}});// Super访问父类var superSayHello = Dreamer.Super.prototype.sayHello;// 暴露给全局命名空间myLib.Dreamer = Dreamer;})();var sylvester = new myLib.Dreamer('Sylvester', 30, 'eating Tweety');
sylvester.sayHello(); //log "Hello from Sylvester! I dream of eating Tweety!"
sylvester.wakeUp(); //log "Wake up!"

c、给类添加新方法

// 给myLib.Dreamer添加新方法
my.extendClass(myLib.Dreamer, {// 添加静态方法
  STATIC : {s_dongSomeThing : function(){console.log("do some thing!");    }},// 添加实例方法touchTheSky: function() {console.log('Touching the sky');},// 添加实例方法reachTheStars: function() {console.log('She is so pretty!');}});

d、实现一个类的方法

// 声明一个新类
myLib.ImaginaryTraveler = my.Class({travel: function() { console.log('Traveling on a carpet!'); },crossOceans: function() { console.log('Saying hi to Moby Dick!'); }
});(function() {//Dreamer 继承 Person 实现 ImaginaryTraveler的方法var Dreamer = my.Class(Person, ImaginaryTraveler, {// 构造方法constructor: function(name, age, dream) {Dreamer.Super.call(this, name, age);this.dream = dream;}// ...
});// 暴露给全局命名空间myLib.Dreamer = Dreamer;})();var aladdin = new Dreamer('Aladdin');
aladdin instanceof Person; //true
aladdin instanceof ImaginaryTraveler; //false
aladdin.travel();
aladdin.wakeUp();
aladdin.sayHello();

如果怕忘记new操作符

var Person = my.Class({//you can now call the constructor with or without newconstructor: function(name, city) {if (!(this instanceof Person))return new Person(name, city);this.name = name;this.city = citye;}});

下面看一下my.class的源代码解析:

my.Class实现思路基本是这样的,如果只有一个参数,那么声明的是一个基础类,这个参数是用来声明新类的方法和属以及构造函数。它不是继承而来,但它可以被继承。

继承的思路,就是如果有两个参数,第一个参数做为父类被继承,第二参数用来声明新类的方法和属性以及构造函数,它同样可以被继承。

如果有三个以上参数那么,除出第一个参数做为继承的父类,最后一个参数用声明新类的方法和属性以及构造函数。中间的参数是用类来扩展新类的方法。当然也可以通过my.extendClass扩展新方法。

同时,类库为commonJS和浏览环境都提供了支持!

/*globals define:true, window:true, module:true*/
(function () {// Namespace objectvar my = {};// 保证AMD分模块可用if (typeof define !== 'undefined')define([], function () {return my;});else if (typeof window !== 'undefined')// 保证客户端可用window.my = my;else// 保证后台可用module.exports = my;//============================================================================// @method my.Class// @params body:Object// @params SuperClass:function, ImplementClasses:function..., body:Object// @return functionmy.Class = function () {var len = arguments.length;var body = arguments[len - 1];    // 最后一个参数是指定本身的方法var SuperClass = len > 1 ? arguments[0] : null;     // 第一个参数是指继承的方法,实例和静态部分均继承var hasImplementClasses = len > 2;    // 如果有第三个参数,那么第二个就是implementClass,这里其实只继承实例对象var Class, SuperClassEmpty;// 保证构造方法if (body.constructor === Object) {Class = function() {};} else {Class = body.constructor;// 保证后面不覆盖constructordelete body.constructor;}// 处理superClass部分if (SuperClass) {// 中间件实现实例属性的继承SuperClassEmpty = function() {};SuperClassEmpty.prototype = SuperClass.prototype;Class.prototype = new SuperClassEmpty();    // 原型继承,解除引用Class.prototype.constructor = Class;    // 保证constructorClass.Super = SuperClass;    // 父对象访问接口// 静态方法继承,重载superClass方法extend(Class, SuperClass, false);}// 处理ImplementClass部分,其实只继承实例属性部分,除SuperClass #arguments[0]# 和 body #arguments[length-1]#if (hasImplementClasses)for (var i = 1; i < len - 1; i++)// implement是继承的实例属性部分, 重载父对象implementClass方法extend(Class.prototype, arguments[i].prototype, false);    // 处理本身声明body部分,静态要STATIC指定,实例部分要删除STATIC部分
    extendClass(Class, body);return Class;};//============================================================================// @method my.extendClass// @params Class:function, extension:Object, ?override:boolean=truevar extendClass = my.extendClass = function (Class, extension, override) {// 静态部分继承静态部分if (extension.STATIC) {extend(Class, extension.STATIC, override);// 保证实例部分不继承静态方法delete extension.STATIC;}// 实例属性继继承实例部
    extend(Class.prototype, extension, override);};//============================================================================var extend = function (obj, extension, override) {var prop;// 其实这里的flase是表明,覆盖父对象的方法if (override === false) {for (prop in extension)if (!(prop in obj))obj[prop] = extension[prop];} else {// 这里其实不覆盖父对象的方法,包括toStringfor (prop in extension)obj[prop] = extension[prop];if (extension.toString !== Object.prototype.toString)obj.toString = extension.toString;}};})();

 二、KLASS

项目地址:https://github.com/ded/klass

先看使用方法:

a、新建一个类

// 声明一个类
var Person = klass(function (name) {this.name = name
}).statics({//静态方法head: ':)',feet: '_|_'}).methods({//实例方法walk: function () {}})

b、继承一个类

// SuperHuman 继承 Person
var SuperHuman = Person.extend(function (name) {// 自动调用父类的构造方法
}).methods({walk: function() {// 显式声明调用父类的walk方法this.supr()this.fly()},fly: function() {}})new SuperHuman('Zelda').walk()

c、字面量方式声明一个类

var Foo = klass({foo: 0,initialize: function() {this.foo = 1},getFoo: function () {return this.foo},setFoo: function (x) {this.foo = xreturn this.getFoo()}
})

d、实现一个类的方法

因为有时候你可能希望覆写或者混合一个实例方法,可以这样:

// 可以传递一个字面量去继承
var Alien = SuperHuman.extend({beam: function() {this.supr()// beam into space
  }
})var Spazoid = new Alien('Zoopo')if (beamIsDown) {// 覆写beam方法
  Spazoid.implement({beam: function() {this.supr()// fallback to jetsthis.jets()}})
}

下面看一下klass源代码解析:

klass的基本设计思路很明确,极力的模仿其它语言的继承方式。比如:子类构造方法调用父类的构造方法,还可以显式的声明调用父类的方法。

这种判断都是基于正则匹配:fnTest = /xyz/.test(function () {xyz;}) ? /\bsupr\b/ : /.*/;关键字"super"

如果显示的声明了要调用父类的方法,那么声明方法的时候,就包装成一个内部调用父类方法且返回相同值的函数,给当前类的方法。

另一方面,构造方法,也是比较灵活的。如果显示的声明了initialize,那么这就是构造方法。否则如果参数是个function那么它就做为构造方法,否则就用父类的构造方法。

通过statics方式添加静态方法,通过实例的implements和静态方法methods添加实例方法。

通过父类的extend实现继承。

同时,类库为commonJS和浏览环境都提供了支持!

/*** Klass.js - copyright @dedfat* version 1.0* https://github.com/ded/klass* Follow our software http://twitter.com/dedfat :)* MIT License*/
!function (context, f) {// fnTest用来验证是否可能通过正则找出调用super父类方法的方法var fnTest = /xyz/.test(function () {xyz;}) ? /\bsupr\b/ : /.*/,noop = function (){},proto = 'prototype',isFn = function (o) {return typeof o === f;};// 基础类function klass(o) {return extend.call(typeof o == f ? o : noop, o, 1);}// 包装成一个借用super同名方法的函数function wrap(k, fn, supr) {return function () {// 缓存原this.supervar tmp = this.supr;// 暂把this.super改造成借用super的同名方法above// 供o里显式的声明(fnTest.text(fn)==true)要借用super的同名方法使用this.supr = supr[proto][k];// 借用执行并保存返回值var ret = fn.apply(this, arguments);// 恢复原this.superthis.supr = tmp;// 返回返回值,保证wrap后的返回值跟原来一致return ret;};}// 如果o和super有同名方法,且o显式声明借用super的同名方法,就wrap成一个待执行函数供使用// 如果没有显式的声明借用super的同名方法,或者是o独有的方法,或者不是方法就直接用function process(what, o, supr) {for (var k in o) {// 如果是非继承方法,按方法注释规则执行,最终都放进whatif (o.hasOwnProperty(k)) {what[k] = typeof o[k] == f&& typeof supr[proto][k] == f&& fnTest.test(o[k])? wrap(k, o[k], supr) : o[k];}}}// 继承方法的实现,fromSub是用来控制是否继承而来,上面的klass里面fromSub是1,表明非继承而来,构造函数不借用super执行function extend(o, fromSub) {// noop做为媒介类实现原型继承的解除引用noop[proto] = this[proto];var supr = this,prototype = new noop(), // 创建实例对象供原型继承使用,解除引用isFunction = typeof o == f,_constructor = isFunction ? o : this,// 如果o是一个构造方法就用,否则由this来决定构造函数_methods = isFunction ? {} : o,    // 如果o是一个{...}应该用methods放到fn原型里,如果里面有initialize就是构造函数,如果o是函数就由上面_constructor决定o是构造函数fn = function () { // 因为kclass借助了kclass,所以最终实际上返回的就是fn,fn其实就新类的构造函数//1 如果o是{...}就会被methods直接过滤并添加到fn的原型里,如果o里面有initialize,那么fn的原型里就有initialize,那么它就是构造方法//2 如果o是function,methods什么也添加不到fn的原型里,但是_constructor会接受o当构造函数//3 如果o是{....},同时里面也没有initialize,那么就是this当构造函数,如果在klass里由call决定,显然构造函数是noop,如果在非基础类里,构造函数就是父类的构造函数//  由于o不是函数不会自动调用父类的构造函数,只是把父类的构造函数当做当前类的构造函数----这都是由于this的指向决定的console.log(this);if (this.initialize) {this.initialize.apply(this, arguments);} else {// 调用父类构造方法// 如上面3,o不是函数,不会调用父类的构造方法// 基础类无父类,不会调用父类构造方法fromSub || isFn(o) && supr.apply(this, arguments);// 调用本类构造方法// 参考上面2,3要么是noop要么是oconsole.log(_constructor==noop);_constructor.apply(this, arguments);}};// 构造原型方法的接口fn.methods = function (o) {process(prototype, o, supr);fn[proto] = prototype;return this;};// 执行实现新类原型,保证新类的constructorfn.methods.call(fn, _methods).prototype.constructor = fn;// 保证新类可以被继承fn.extend = arguments.callee;// 添加实例方法或者静态方法,statics:静态方法,implement实例方法fn[proto].implement = fn.statics = function (o, optFn) {// 保证o是一个object对象,如果o是一个字符串,那么就是添一个方法的情况,如果o是一个object对象说明是批量添加的// 因为要从o里面拷贝o = typeof o == 'string' ? (function () {var obj = {};obj[o] = optFn;return obj;}()) : o;// 添加实例方法或者静态方法,statics:静态方法,implement实例方法process(this, o, supr);return this;};return fn;}// 后台用,nodejsif (typeof module !== 'undefined' && module.exports) {module.exports = klass;} else {var old = context.klass;// 防冲突klass.noConflict = function () {context.klass = old;return this;};// 前台浏览器用//window.kclass = kclass;context.klass = klass;}}(this, 'function');

 三、还有一种简单实现

实现思路很简单,就是利用ECMAScript 5 原型式继承Object.create方法,封装成一个方法,如果不支持ECMAScript5的环境,就平移退化到

function F() {};
F.prototype = superCtor.prototype;
ctor.prototype = new F();
ctor.prototype.constructor = ctor;

同样的,除最后一个参数是当前类的方法声明,其它参数均做为继承父类,需要循环继承,但当这里处理的相对比较简单,没涉及到覆盖。你可以自己动手添加。

var Class = (function() {  /**  * Inherits function.(node.js)  *   * @param ctor subclass's constructor.  * @param superctor superclass's constructor.  */  var inherits = function(ctor, superCtor) { // 显式的指定父类ctor.super_ = superCtor;  // ECMAScript 5  原型式继承并解除引用if (Object.create) {  ctor.prototype = Object.create(superCtor.prototype, {  constructor: {  value: ctor,  enumerable: false,  writable: true,  configurable: true  }  });  } else {  // 无Object.create方法的平稳退化function F() {};  F.prototype = superCtor.prototype;  ctor.prototype = new F();  ctor.prototype.constructor = ctor;  }  };  /**  * Class function.  */  return function() {  // 最后一个参数是新类方法、属性和构造函数声明var subClazz = arguments[arguments.length - 1] || function() {};  // initialize是构造函数,否构造函数就是一个空函数var fn = subClazz.initialize == null ? function() {} : subClazz.initialize;  // 继承除最一个参数以的类,多继承,也可以用作扩展方法 for (var index = 0; index < arguments.length - 1; index++) {  inherits(fn, arguments[index]);  }  // 实现新类的方法for (var prop in subClazz) {  if (prop == "initialize") {  continue;  }  fn.prototype[prop] = subClazz[prop];  }  return fn;  }  })(); 

看下面实例:

/**  * The definition of Cat Class.  */
var Cat = Class({  /**  * Constructor.  *   * @param name Cat's name  */  initialize: function(name) {this.name = name;  },  /**  * Eat function.  */  eat: function() {  alert(this.name + " is eating fish.");  }
});  /**  * The definition of Black Cat Class.  */
var BlackCat = Class(Cat, {  /**  * Constructor.  *   * @param name Cat's name.  * @param age Cat's age.  */  initialize: function(name, age) {  // call the constructor of super class.  BlackCat.super_.call(this, name);  this.age = age;  },  /**  * Eat function.  */  eat: function() {  alert(this.name + "(" + this.age + ") is eating dog.");  }
});  /**  * The definition of Black Fat Cat Class.  */
var BlackFatCat = Class(BlackCat, {  /**  * Constructor.  *   * @param name Cat's name.  * @param age Cat's age.  * @param weight Cat's weight.  */  initialize: function(name, age, weight) {  // call the constructor of super class.  BlackFatCat.super_.call(this, name, age);  this.weight = weight;  },  /**  * Eat function.  */  eat: function() {  alert(this.name + "(" + this.age + ") is eating dog. My weight: " + this.weight);  }
});  /**  * The definition of Dog Class.  */
var Dog = Class({});  var cat = new BlackFatCat("John", 24, "100kg");
cat.eat();  // true
alert(cat instanceof Cat);  // true
alert(cat instanceof BlackCat);  // true
alert(cat instanceof BlackFatCat);  // true
alert(cat.constructor === BlackFatCat);  // false
alert(cat instanceof Dog);  

 四、mootools类库的Class

源码解析可以看这里:http://www.cnblogs.com/hmking/archive/2011/09/30/2196504.html

看具体用法:

a、新建一个类

var Cat = new Class({initialize: function(name){this.name = name;}
});
var myCat = new Cat('Micia');
alert(myCat.name); // alerts 'Micia'var Cow = new Class({initialize: function(){alert('moooo');}
});

b、继承的实现

var Animal = new Class({initialize: function(age){this.age = age;}
});
var Cat = new Class({Extends: Animal,initialize: function(name, age){this.parent(age); // calls initalize method of Animal classthis.name = name;}
});
var myCat = new Cat('Micia', 20);
alert(myCat.name); // alerts 'Micia'.
alert(myCat.age); // alerts 20.

c、扩充类的实现

var Animal = new Class({initialize: function(age){this.age = age;}
});
var Cat = new Class({Implements: Animal,setName: function(name){this.name = name}
});
var myAnimal = new Cat(20);
myAnimal.setName('Micia');
alert(myAnimal.name); // alerts 'Micia'.

由于写的比较笼统,可能有很多地方没有解析到,也可能有不准确的地方,还望指正。

看完上面几种解析,相信息自己也可以写出一个自己的封装类库出来,至于,怎么实现看个人喜好了。但基本的思都是一样的基于原型的继承方式和循环拷贝新方法。

javascript面向对象包装类Class的类库解析相关推荐

  1. JavaScript面向对象——封装及相关原理解析

    <JavaScript设计模式>面向对象编程--封装及相关原理解析 说明:本人编写js习惯不写分号:文章中的源码可根据自己的编程风格修改. 面向对象 面向对象编程就是将你的需求抽象成一个对 ...

  2. JavaScript面向对象编程

    自从有了Ajax这个概念,JavaScript作为Ajax的利器,其作用一路飙升.JavaScript最基本的使用,以及语法.浏览器对象等等东东在这里就不累赘了.把主要篇幅放在如何实现JavaScri ...

  3. 用JSON和Javscript的prototype来构建完善的Javascript面向对象表示法

    [原文地址:http://www.cnblogs.com/robinhood/archive/2006/11/16/515412.html] 上次发贴没能很好的总结Javascrip编写类的方法,这次 ...

  4. 《javascript面向对象编程指南》读书笔记

    <javascript面向对象编程指南>读书笔记 <javascript面向对象编程指南>读书笔记 第一章 面向对象的JavaScript 第二章 基本数据类型与流程控制 变量 ...

  5. javascript 在对象中使用 定时器_如何使用JavaScript 面向对象编程

    学习目标 理解面向对象开发思想 掌握 JavaScript 面向对象开发相关模式 面向对象介绍 什么是对象 Everything is object (一切皆对象) 我们可以从两个层次来理解对象: ( ...

  6. 【javascript面向对象之路】让我们一起来坦克大战吧01

    提问 不知道大家发现没有,运行时候浏览器或者电脑会变得很卡哦.根据我们之前的学习,你知道是什么原因导致的吗? 若是各位有兴趣,请你回答卡的原因,并提出优化方案.  前言 PS 各位要看效果还是使用ff ...

  7. JavaScript面向对象编程-第三版不完全系统解读

    JavaScript面向对象编程-第三版不完全系统解读 作者:老九-技术大黍 产品:查看原文 社交:知乎 公众号:老九学堂(新手有福利) 特别声明:原创不易,未经授权不得转载或抄袭,如需转载可联系笔者 ...

  8. JavaScript 面向对象编程思想简介

    JavaScript 面向对象编程 JavaScript 执行过程 JavaScript 面向对象编程 面向对象介绍 什么是对象 什么是面向对象 程序中面向对象的基本体现 创建对象 简单方式 简单方式 ...

  9. JavaScript 面向对象编程思想

    JavaScript 面向对象编程思想 什么是面向对象 面向对象不是新的东西,它只是过程式代码的一种高度封装,目的在于提高代码的开发效率和可维护性. 面向对象编程 -- Object Oriented ...

最新文章

  1. Eclipse如何更改包名后,批量修改文件的包名
  2. 聚类效果评估、内部指标(Jaccard系数、FM指数、Rand指数)、外部指标(DB指数、Dunn指数)、轮廓系数(Silhouette Coefficient)
  3. xshell添加脚本
  4. Python教程:自定义排序全套方案
  5. 等了这么久,就给我看这个?
  6. 傅里叶变换表_Numpy库小抄表!主要语法和代码都在这里啦
  7. nsct matlab,图像融合 NSCT算法 matlab
  8. html图片倒角,CSS实例:纯CSS打造斜角
  9. main函数默认参数argc和argv的详解
  10. 助创cms众筹 php,【教程】助创cms众筹系统完整测试流程详解
  11. Verifying transaction: | WARNING conda.core.path_actions:verify(962): Unable to create environments
  12. 安川机器人梯形图指令(三)
  13. 实验一计算机基础和网络知识竞赛,第十三届计算机基础知识竞赛题库.doc
  14. 希尔伯特变换到底有什么用
  15. HTTP 协议中的长连接和短连接
  16. vant 动态 粘性布局_使用 position:sticky 实现粘性布局
  17. 笔记本触摸屏使用技巧
  18. 文件加密系统是如何实现企业数据高效安全保护的?
  19. 学习FPGA之四:FPGA开发方法
  20. 大数据4V+1C 的特征

热门文章

  1. Eclipse Code Review(代码审查)工具介绍
  2. 毛坯房装修需要哪些材料
  3. js 字符转换,小驼峰转大写字母开头并且加空格 changeDate -》 Change Date
  4. Jenkins命令可视化
  5. 1.1 sql注入分类与详解
  6. mysql第四篇:数据操作之多表查询
  7. java-final关键字
  8. ListView添加项目带序列
  9. Android 获取WebView的内容宽度高度
  10. C# — 创建Windows服务