Js 继承:extend、mixin和plugin(一)

简介:

我们编写前端控件时,需要给控件建立一个体系,面向对象是一个很合适的方式,但是JS本身对面向对象的一些概念支持偏弱,特别是继承的特性方面,那么我们就必须通过一系列的方式来实现继承。

Extend方式:

Extend方式非常贴近面向对象语言中的类继承,这种方式使用原型链的方式来实现继承。原型链的继承方式有几个缺点:

1)缺少针对父类的引用,例如:

function A(){

//初始化A操作

}

A.prototype = {

method1:function(){

//A的一系列操作

}

}

function B(){

//初始化B的操作

}

B.prototype = new A();

B.method1 = function(){

//先执行 A.method1的方法

//执行自己的方法

}

那么此时如何在调用A的method1方法呢?我们没有java中的’super’对象也缺少C#中的’base’对象,当然我们可以换一种写法,来解决这个问题:

var  aobj = new A();

B.prototype = aobj;

B.method1 = function(){

aobj.method1.call(this);//先执行 A.method1的方法

//执行自己的方法

}

但是我们必须能缓存刚才的 aobj对象,方便在调用B.method1时取得到,所以我们就引入’superclass’字段,放在构造函数B上作为静态属性,调用时:B.superclass.method1.call(this),下面是实现:

function extend(subclass,superclass){

var superObj = new superclass();

subclass.prototype = superObj;

subclass.superclass = superObj;

return subclass;

}

上面的函数解决了superclass的问题但是又引入了新的问题,下面我们一一来讲。

2)破坏了对象的constructor属性,这个属性在使用继承的过程中非常有用,它指向的是对象的构造函数,例如:

function A(){}

//未继承 A时

function B(){}

var b = new B();

alert(b.constructor === B) //true

//B继承A

extend(B,A);

b1 = new B();

alert(b1.constructor === B) // false

alert(b1.constructor === b.constructor) //false

这样的结果绝对不是我们需要的,否则我们在编写方法的过程中调用,B.supercalss.constructor.call(this) 或者 B.superclass.constructor.superclass 会出现混乱,我们怎么办呢,继续改进extend方法,矫正constructor 属性:

function extend(subclass,superclass){

  var superObj = new superclass();

  subclass.prototype = superObj;

superObj.constructor = subclass;//矫正 constructor属性

  subclass.superclass = superObj;

  return subclass;

}

到这里看似解决了继承链的问题,但是此时我们来看一下下面情形:

function C (){}

extend(C,B);

var c = new C();

alert(c.constructor.superclass.constructor);//C

上面的结果意外的不是B 而是 C,这是什么原因呢,我们看刚才矫正constructor 属性以及上面一句:

subclass.prototype = superObj;

superObj.constructor = subclass;

我们将C的prototype的constructor修改为了C ,由于subclass.superclass = superObj;那么C的superclass跟C 的prototype是同一个对象,那么 c.constructor.superclass.constructor等同于C.prototype.constructor 结果就是 C,那么我们需要做一下修改:

function extend(subclass,superclass){

  var superObj = new superclass();

  subclass.prototype = superObj;

superObj.constructor = subclass;//矫正 constructor属性

  subclass.superclass = new superclass();

  return subclass;

}

此时我们再来调用一下:

alert(c.constructor.superclass.constructor);//B

此时的还有什么问题呢?我们来做一下实验:

function A (config){

console.log('a constructor,config:' + config);

}

A.prototype = {

method : function(){

console.log('a runing');

}

};

function B (config){

this.constructor.superclass.constructor.call(this,config);

console.log('b constructor,config:' + config);

}

extend(B,A);

function C (config){

this.constructor.superclass.constructor.call(this,config);

console.log('c constructor,config:' + config);

}

extend(C,B);

var c = new C('hello');

c.method();

输出结果:

a constructor,config:undefined

a constructor,config:undefined

b constructor,config:undefined

b constructor,config:undefined

b constructor,config:undefined

Uncaught RangeError: Maximum call stack size exceeded

我们看到没有输出我们希望的结果,这里有2个问题,

1. 产生了循环调用

2. 未实例化对象前,实例化了多个父类对象,而且这些实例初始化时传入的参数为空,极易出现错误。

解决死循环我们只需要把this.constructor.superclass 替换为 对应的 B.superclass即可:

function B (config){

B.superclass.constructor.call(this,config);

console.log('b constructor,config:' + config);

}

function C (config){

C.superclass.constructor.call(this,config);

console.log('c constructor,config:' + config);

}

针对调用extend时生成多个实例我们引入方法:

function create(proto, c) {

function F() {

}

F.prototype = proto;

var o = new F();

o.constructor = c;

return o;

}

在extend方法中我们这样调用:

var superObj = create(superclass.prototype,subclass);

subclass.prototype = superObj;

subclass.superclass = create(superclass.prototype,superclass);

此时我们的prototype 属性和superclass属性都不需要实例化对象,完整的extend方法如下:

function extend(subclass,superclass){

function create(proto, c) {

function F() {

}

F.prototype = proto;

var o = new F();

o.constructor = c;

return o;

}

  var superObj = create(superclass.prototype,subclass);

subclass.prototype = superObj;

subclass.superclass = create(superclass.prototype,superclass);

  return subclass;

}

这样在执行上面的代码即得到:

a constructor,config:hello

b constructor,config:hello

c constructor,config:hello

a runing

今天先写到这里,接下来我会把控件的继承机制一下,如果有时间,把一些编写js控件的经验分享出来,希望对大家有帮助。

转载于:https://www.cnblogs.com/zaohe/archive/2012/10/13/2723148.html

Js 控件编写 继承:extend、mixin和plugin(一)相关推荐

  1. .net firamework 框架里面的控件的继承关系。

    记得当初学习VB6.0的时候,入门的书,一上来就是控件的介绍,控件的属性.事件的使用,拖拽一个文本框.一个按钮,然后再双击按钮,在按钮的事件里面给文本框的Text 设置一个"hello wo ...

  2. Android控件的继承关系图

    Android中所有控件都继承自android.view.View,其中android.view.ViewGroup是View的一个重要子类,绝大部分的布局都继承自ViewGroup. 下面是安卓控件 ...

  3. 如何利用Winsock控件编写自己的Internet程序

    VB自带的Winsock控件是一个非常强大的工具,利用它你可以在你的程序中使用各种Internet协议.如果你对网络协议及计算机之间通信的原理有所了解的话,理论上讲你可以编写任何Internet程序. ...

  4. android 继承现有控件,Android继承现有控件拓展实现自定义控件textView

    通常情况下,Android实现自定义控件无非三种方式. Ⅰ.继承现有控件,对其控件的功能进行拓展. Ⅱ.将现有控件进行组合,实现功能更加强大控件. Ⅲ.重写View实现全新的控件 本文重点讨论继承现有 ...

  5. VS2008下用MFC 的MSComm控件编写串口程序

    可以在:http://download.csdn.net/detail/plutus_lee/4525446 下载详细文档. 首先感谢网络资源吧,作为一个自动化专业出身的,不懂串口实在让我有点无奈,本 ...

  6. Auto.js 控件属性缺失时获取控件

    Auto.js 在控件属性缺失情况下获取控件 群里有很多新人问,各种既没有id也没有text的控件无法获取的问题. 文章目录 Auto.js 在控件属性缺失情况下获取控件 使用环境 一.具体操作 只用 ...

  7. c#—如何借助windows media player控件编写播放器

    windows media player控件的常用属性和方法 以下 music player 均为windows media player控件的名字. 1.属性  1)musicPlayer.sett ...

  8. html 关闭js控件,javascript – 用JS关闭html5视频控件

    我有一个问题, html5视频控件捕获在iOS上发生的任何动作,这干扰了我需要在视频上显示的模态窗口. 我正在尝试自定义模态本身,但似乎无法使其工作.基本上,当模态打开时,我需要做: var vide ...

  9. python爬silverlight_Python创建Silverlight控件编写过程经验分享

    Python编程语言可以帮助我们实现哪些功能呢?它的主要应用范围都包括哪些呢?我们今天先来了解一下有关Python创建Silverlight控件的相关实现方法,以此来初步熟悉一下这一语言的应用方式以及 ...

最新文章

  1. linux c open fopen freopen 文件操作函数
  2. portal开发下拉框“日期框”查询要怎么配置
  3. sharepoint当流程流转到某个节点对文档进行水印操作
  4. mysql 读取oracle_RobotFramework读取mysql和oracle数据库
  5. 使用Zabbix Agent 2监控MongoDB
  6. HDU 5570:balls 期望。。。。。。。。。。。。。。。
  7. 2020-07-05
  8. 活动报名 | 无限视觉生成模型NUWA-Infinity,可生成超3万像素清明上河图
  9. 无法使用计算机名访问共享,局域网内无法用计算机名访问共享的解决办法
  10. arduino等开源平台
  11. 认识和使用热插拔的正确姿势
  12. Js中Date日期的使用(加一天,加一个月,获取0时0分0秒,23时59分59秒等)
  13. 白话数字签名(2)——软件设备
  14. Python 使用Opencv读写视频(Opencv教程二)
  15. 电网电压的三相静止对称坐标系和三相电网电压的相量表示法
  16. python出现 'ascii' codec can't decode byte 0xXX in position XX: ordinal not in range(128)问题
  17. 我用python分析了李子柒的辣酱真的好吃吗?
  18. FPS手游逆向分析--------矩阵
  19. 珍爱网退费流程?珍爱网怎么退费
  20. 完全背包问题Leecode322零钱兑换和Leecode518零钱兑换||

热门文章

  1. 订阅广告一个微博大号的微信生存记
  2. 和菜鸟一起学c++之虚函数
  3. tablespaces-datafiles示意图
  4. 白领丽人:这六行盛产“钻石王老五”
  5. SSH的端口转发:本地转发Local Forward和远程转发Remote Forward
  6. 8.8-9 fsck、dd
  7. android studio 反编译工具,android studio反编译工具jd-inteIIij
  8. cs架构嵌入bs_车牌识别CS架构和BS架构详解
  9. java控制语句案例_Java基础语法—流程控制语句
  10. linux nginx 安装stream,Centos7下Nginx简单搭建与stream模块简单配置