js并不是一种面向对向的语言, 没有提供对类的支持, 因此我们不能像在传统的语言里那样 用class来定义类, 但我们可以利用js的闭包封装机制来实现js类, 我们来封装一个简的Shape类.

1. 定义js类 js并不是一种面向对向的语言, 没有提供对类的支持, 因此我们不能像在传统的语言里那样 用class来定义类, 但我们可以利用js的闭包封装机制来实现js类, 我们来封装一个简的Shape类.

代码如下:
  1. function ShapeBase() {
  2. this.show = function() {
  3. alert("ShapeBase show");
  4. };
  5. this.init = function(){
  6. alert("ShapeBase init");
  7. };
  8. }

这个类里定义了两个方法:show和init, 需要注意的是这里用到了this来声明, 而不是var, 因为用var是用来定义私有方法的. 另外, 我们还可以用prototype属性来定义Shape的方法.

 代码如下:
  1. ShapeBase.prototype.show=function() {
  2. alert("ShapeBase show");
  3. }
  4. ShapeBase.prototype.init=function() {
  5. alert("ShapeBase init");
  6. }

上面这种写法看起来不太直观,我们可以将所有的方法写在一起.

代码如下:
  1. ShapeBase.prototype={
  2. show:function() {
  3. alert("ShapeBase show");
  4. },
  5. init:function() {
  6. alert("ShapeBase init");
  7. }
  8. };

现在, 类是写好了, 让我们写个js来测试下, 看看结果是不是跟我们想象的一样呢?

 代码如下:
function test(src){ var s=new ShapeBase(); s.init(); s.show(); }

看到了吧, 其调用方式和C#一模一样, 而结果也如我们所料. 到目前为止, 我们学会了如何创建js的类了, 但还只是实例方法,要是实现跟C#中的静态方法要怎么做呢? 其实, 实现js的静态方法很简单, 看下面如何实现:

 代码如下:
//静态方法 ShapeBase.StaticDraw = function() { alert("method draw is static"); }

2. 实现JS类抽象和继承 同样, js中也不支持类继承机制,但我们可以通过将父类prototype中的成员方法复制到子类的prototype中来实现.
和类的继承一样,JavaScript也没有任何机制用于支持抽象类.但利用JavaScript语言本身的性质.可以实现自己的抽象类.
首先来看看js中的虚方法, 在传统语言中虚方法是要先定义的, 而包含虚方法的类就是抽象类,不能被实例化,而在JavaScript中,虚方法就可以看作该类中没有定义的方法,但已经通过this指针使用了.
和传统面向对象不同的是,这里虚方法不需经过声明,而直接使用了, 并且类也可以被实例化. 先定义object的extend方法, 一个为静态方法,一个为实例方法, 这两个方法用于实现继承的prototype复制

代码如下:
  1. Object.extend = function(destination, source) {
  2. for (property in source) {
  3. destination[property] = source[property];
  4. }
  5. return destination; }
  6. Object.prototype.extend = function(object) {
  7. return Object.extend.apply(this, [this, object]); }

接下来我们实现一个继承类Rect, 这里先用一种简单的方法来实现。

代码如下:
  1. function Rect() {
  2. }
  3. Rect.prototype = ShapeBase.prototype; //只这一句就行了 //扩充新的方法 Rect.prototype.add=function() {
  4. alert("Rect add");
  5. }

这种方法不能用于重写,如果改变了show方法, ShapeBase的show也会指向同一函数可能是由于prototype赋值只是简单的改变指向地址. 如果上面也定义了:
Rect.prototype.show=function() { alert("Rect show"); } 那么执行结果如下:
function test(){ var s=new ShapeBase(); s.show(); //结果:Rect show
var r=new Rect(); r.show(); //结果:Rect show r.add(); }
我们再使用object.extend实现继承, 并实现一个oninit虚方法, 修改ShapeBase如下:

 代码如下:
  1. ShapeBase.prototype={
  2. show:function() {
  3. alert("ShapeBase show");
  4. },
  5. initialize:function () {
  6. this.oninit();
  7. }
  8. };

实现Rect类继承.

代码如下:
Rect.prototype=(new ShapeBase).extend({
//添加新的方法 add:function() { alert("Rect add"); },
//使用这种方法可以重写show方法 show:function() { alert("Rect show"); },
//实现虚方法 oninit:function() { alert("Rect oninit"); } })

现在我们的类写好了, 测试下看看:

 代码如下:
  1. function test(src){
  2. ShapeBase.StaticDraw();
  3. var s=new ShapeBase();
  4. s.show(); //alert("ShapeBase show")
  5. var r=new Rect();
  6. r.show(); //alert("Rect show")
  7. r.add();
  8. r.initialize(); //alert("Rect oninit") }

另外,在网上看到一篇用专门的对象来创建类,代码如下:

代码如下:
  1. function extend(des, src) {
  2. if (!des)
  3. des = {};
  4. if (src) {
  5. for (var i in src) {
  6. des[i] = src[i];
  7. }
  8. }
  9. return des;
  10. }
  11. var CC = {}; //全局变量
  12. //
  13. //create 用于创建类
  14. //
  15. CC.create = function(superclass, constructor){
  16. var clazz = (function() {
  17. this.initialize.apply(this, arguments);
  18. });
  19. //如果无参数,直接返回类.
  20. if(arguments.length == 0)
  21. return clazz;
  22. //如果无父类,此时constructor应该为一个纯对象,直接复制属性返回.
  23. if(!superclass){
  24. extend(clazz.prototype, constructor);
  25. return clazz;
  26. }
  27. var absObj = clazz.prototype,
  28. sprPropty = superclass.prototype;
  29. if(sprPropty){
  30. //用于访问父类方法
  31. clazz.superclass = sprPropty;
  32. extend(absObj, sprPropty);
  33. //调用属性构造函数创建属性,这个是实现关键.
  34. extend(absObj, constructor(sprPropty));
  35. // 子类实例直接通过obj.superclass访问父类属性,
  36. // 如果不想造成过多引用,也可把这句注释掉,因为多数时候是没必要的.
  37. absObj.superclass = sprPropty;
  38. //
  39. clazz.constructor = constructor;
  40. }
  41. return clazz;
  42. }
  43. //
  44. //创建一个动物类
  45. //
  46. var Animal = CC.create(null, {
  47. //属性
  48. footprint : '- - - - - - =',
  49. //类初始化方法,必须的,当用 new 生成一个类时该方法自动被调用,参见上定义.
  50. initialize : function(options){
  51. extend(this, options);
  52. alert('Animal initialize method is called.');
  53. },
  54. eat : function(){
  55. alert('Animal eat method is called.');
  56. },
  57. move : function(){
  58. alert('I am moving like this '+ this.footprint +' .');
  59. }
  60. });
  61. //
  62. //创建一个Duke类
  63. //
  64. var Duke = CC.create(Animal, function(superclass){
  65. //在这可以定义一些类全局静态数据,该类每个实例都共享这些数据.
  66. //计算实例个类,包括派生类实例.
  67. var static_instance_counter = 0;
  68. function classUtilityFuncHere(){ }
  69. //返回类具体属性.
  70. return {
  71. //重写初始化方法
  72. //@override
  73. initialize : function(options) {
  74. alert('Initializing Duke class..');
  75. //调用父类初始化,这种方法比一般其它库的要简洁点吧,可以不管父类是什么.
  76. superclass.initialize.call(this, options);
  77. //做一些子类喜欢做的事.
  78. alert('Duke initialize method is called.');
  79. //读取或修改类静态属性
  80. static_instance_counter++;
  81. },
  82. //重写move方法,增加Duke自己的移动方式.
  83. move : function(){
  84. this.footprint = this.footprint + 'zzzzzzzz';
  85. superclass.move.call(this);
  86. },
  87. //重写eat方法,注意,里面不调用父类方法,即父类eat被覆盖了.
  88. eat : function(){
  89. alert('Duke is eating..');
  90. },
  91. //新增一个say方法,显示当前已经初始化的Duke类实例数量.
  92. say : function(){
  93. alert('the number of Duke instances is '+static_instance_counter);
  94. }
  95. };
  96. });
  97. var DukeChild = CC.create(Duke, function(superclass){
  98. return {
  99. move : function(){
  100. this.footprint = this.footprint + '++++++++++++=';
  101. superclass.move.call(this);
  102. },
  103. say : function(){
  104. alert(this.msg || '');
  105. }
  106. };
  107. });
  108. (function test() {
  109. var animal = new Animal();
  110. animal.eat();
  111. animal.move();
  112. var dukeA = new Duke();
  113. dukeA.eat();
  114. dukeA.move();
  115. dukeA.say();
  116. var dukeB = new Duke();
  117. dukeB.eat();
  118. dukeB.move();
  119. dukeB.say();
  120. var dukeC = new DukeChild({msg : 'I am a child of duke.'});
  121. dukeC.move();
  122. dukeC.say();
  123. })();
 

JS类的封装及实现代码的更多相关文章

  1. 自己手写的自动完成js类

    在web开发中,为了提高用户体验,会经常用到输入框的自动完成功能,不仅帮助用户进行快速输入,最重要的是帮助那些“记不全要输入什么”的用户进行选择.这个功能有很多插件已经实现了,为了适应项目的特殊需求, ...

  2. js类(继承)(二)

    1. 定义js类 js并不是一种面向对向的语言, 没有提供对类的支持, 因此我们不能像在传统的语言里那样 用class来定义类, 但我们可以利用js的闭包封装机制来实现js类, 我们来封装一个简的Sh ...

  3. 【转】第7篇:Xilium CefGlue 关于 CLR Object 与 JS 交互类库封装报告:全自动注册与反射方法分析

    作者: 牛A与牛C之间 时间: 2013-12-12 分类: 技术文章 | 2条评论 | 编辑文章 主页 » 技术文章 » 第7篇:Xilium CefGlue 关于 CLR Object 与 JS ...

  4. 【转】第6篇:Xilium CefGlue 关于 CLR Object 与 JS 交互类库封装报告:自动注册JS脚本+自动反射方法分析

    作者: 牛A与牛C之间 时间: 2013-11-21 分类: 技术文章 | 暂无评论 | 编辑文章 主页 » 技术文章 » 第6篇:Xilium CefGlue 关于 CLR Object 与 JS ...

  5. 【转】第5篇:Xilium CefGlue 关于 CLR Object 与 JS 交互类库封装报告:自动注册JS脚本+委托回调方法分析

    作者: 牛A与牛C之间 时间: 2013-11-19 分类: 技术文章 | 暂无评论 | 编辑文章 主页 » 技术文章 » 第5篇:Xilium CefGlue 关于 CLR Object 与 JS ...

  6. 【转】第4篇:Xilium CefGlue 关于 CLR Object 与 JS 交互类库封装报告:委托回调方法分析

    作者: 牛A与牛C之间 时间: 2013-11-18 分类: 技术文章 | 暂无评论 | 编辑文章 主页 » 技术文章 » 第4篇:Xilium CefGlue 关于 CLR Object 与 JS ...

  7. 【转】3篇:Xilium CefGlue 关于 CLR Object 与 JS 交互类库封装报告:官方原生方法分析

    作者: 牛A与牛C之间 时间: 2013-11-17 分类: 技术文章 | 暂无评论 | 编辑文章 主页 » 技术文章 » 第3篇:Xilium CefGlue 关于 CLR Object 与 JS ...

  8. JS类继承常用方式发展史

    JS类继承常用方式发展史 涉及知识点 构造函数方式继承 1-继承单个对象 1.1 多步走初始版 1.2 多步走优化版 1.3 Object.create()方式 2-继承多个对象 2.1 遍历 Obj ...

  9. JS对象之封装(二)

    JS 对象封装的常用方式 1.常规封装 function Person (name,age){ this.name = name; this.age = age; } Pserson.prototyp ...

随机推荐

  1. MVC基础知识 – 2.新语法

    1.自动属性 Auto-Implemented Properties 2.隐式类型 var 3.参数默认值 和 命名参数 4.对象初始化器 与 集合初始化器 { } 5.匿名类 & 匿名方法 ...

  2. 微信token验证失败的解决方法

    一.问题由来 在使用URL和Token启用微信公众平台开发模式消息接口的时候,我们会碰到下面三种情况 1. token校验失败 这样回头检查一下各项配置是否正确.如果确定配置没有问题,请按下面的方法检 ...

  3. 使用Autofac在ASP.NET Web API上实现依赖注入

    在ASP.NET Web API里使用Autofac 1.通过NuGet安装Autofac.WebApi(当时安装的是Autofac 3.1.0) PM > Install-Package Au ...

  4. Powershell查看SSAS Cube占用磁盘空间

    以下是用powershell查看Cube占用磁盘空间大小的方式.可以编译成函数也可以直接把参数改成需要的服务器名称. Param($ServerName="SERVERNAME") ...

  5. golang time and duration

    package mainimport "fmt"import "time"func main() { p := fmt.Println // We'll sta ...

  6. 计算G711语音的打包长度和RTP里timestamp(时间戳)的增长量

    转自:http://blog.csdn.net/xujianglun/article/details/48342367 如何计算G711语音等的打包长度和RTP里timestamp的增长量 一般对于不 ...

  7. hpunix下11gRac的安装

    一.检查环境 1.操作系统版本# uname -a 2.补丁包三大补丁包#swlist -l bundle|grep QPKAPPS#swlist -l bundle|grep QPKBASE#swl ...

  8. 第三篇:用SOUI能做什么?

    SOUI-DEMO界面预览 在回答SOUI能做什么之前,先看看SVN中demo工程的界面截图: 使用SOUI实现上面的界面主要的工作全在配置几个XML文件,基本不需要写C++代码.(如何配置XML布局 ...

  9. android在代码中四种设置控件(以及TextView的文字颜色)背景颜色的方法

      http://blog.csdn.net/fth826595345/article/details/9208771 主题 TextView 转载请注明出处: http://blog.csdn.ne ...

  10. ios录音

    #import "ViewController.h" #import <AVFoundation/AVFoundation.h> @interface ViewCont ...