学习JavaScript设计模式(继承)


Posted in Javascript onNovember 26, 2015

1、继承

在javascript中继承是一个非常复杂的话题,比其他任何面向对象语言的中的继承都复杂得多。在大多数其他面向对象语言中,继承一个类只需要使用一个关键字即可。与它们不同,在javascript中要想达到传承公用成员的目的,需要采取一系列措施。更有甚者,javascript属于使用原型式继承的少数语言之一。利益于这种语言的灵活性,你既可使用标准的基于类的继承,也可使用更微妙一些的原型式继承。

2、为什么需要继承?

一般来说,在设计类的时候,我们希望能减少重复性的代码,并且尽量弱化对象间的耦合。使用继承符合前一个设计原则的需要。借助这种机制,你可以在现有类的基础上进行设计并充分利用它们已经具备的各种方法,而对设计进行修改也更为轻松。假设你需要让几个类都拥有一个按特定方式输出类结构的toString()方法,当然可以用复制加粘贴的办法把定义toString()方法的代码添加到每一个类中,但这样做的话,每当需要改变这个方法的工作方式时,你将不得不在每一个类中重复同样的修改。反之,如果你提供了一个ToStringProvider类,然后让那些类继承这个类,那么toString这个方法只需在一个地方声明即可。

让一个类继承另一个类可能会导致二者产生强耦合,也即一个类的依赖于另一个类的内部实现。我们将讨论一些有助于避免这种问题的技术,其中包括用掺元类为其他类提供方法这种技术。

3、基于类的继承

下面看下面的代码:

<script type="text/javascript"> 


  function Person(name, age) 
  { 
   this.name = name; 
   this.age = age; 
  } 
  Person.prototype.say = function () 
  { 
   console.log(this.name + " , " + this.age); 
  } 
  function Student(no) 
  { 
   this.no = no; 
  } 
  /** 
   * Student的prototype指向Person的对象 
   */</span> 
  Student.prototype = new Person(); 
  var stu1 = new Student("0001"); 
  stu1.name = '张三'; 
  stu1.age = '11'; 
  console.log(stu1.no); 
  stu1.say(); 
 </script>

输出结果:  
张三 , 11  
可以看到Student成功集成了Person,并且拥有了Person的say方法,核心代码其实就是一句 Student.prototype = new Person();,下面通过图解来说明原理:

学习JavaScript设计模式(继承)

将Student.prototype指向new Person() , new Person的_proto_又指向Person Prototype;这样完成了整个继承。

但是这种方式存在问题:

问题1:当父类存在引用类型变量时,造成数据不一致,下面我们给Person添加一个hobbies属性,类型为数组。

<script type="text/javascript"> 
  /** 
  * 存在问题 
  * 1、无法在Student的构造方法中传递参数用于父类的构造方法 
  * 2、对于引用类型变量,造成数据不一致 
  */ 


  function Person(name, age) 
  { 
   this.name = name; 
   this.age = age; 
   this.hobbies = [] ; 
  } 
  Person.prototype.say = function () 
  { 
   console.log(this.name + " , " + this.age +" , " +this.hobbies); 
  } 
  function Student(no) 
  { 
   this.no = no; 
  } 
  Student.prototype = new Person(); 

  var stu1 = new Student("0001"); 
  stu1.name = '张三'; 
  stu1.age = '11'; 
  stu1.hobbies.push("soccer"); 
  stu1.say(); 

  var stu2 = new Student("0002"); 
  stu2.name = '李四'; 
  stu2.age = '12'; 
  stu2.hobbies.push("girl"); 
  stu2.say(); 
 </script>

输出结果:
张三 , 11 , soccer  
李四 , 12 , soccer,girl  
可以看出,李四的hobbies应该只有girl,但是上面的代码让所有对象共享了hobbies属性。
上述的继承方式还存在一个问题:

问题2:在Student的构造方法中,无法使用new Student(“00001” , “张三” , 12) ;创建对象,并初始化name和age属性,必须stu.name, stu.age进行赋值

为了解决上述问题,对上述代码进行修改:

<script type="text/javascript"> 

  function Person(name, age) 
  { 
   this.name = name; 
   this.age = age; 
   this.hobbies = []; 
  } 
  Person.prototype.say = function () 
  { 
   console.log(this.name + " , " + this.age +" , " + this.hobbies); 
  } 

  function Student(name, age, no) 
  { 
   /** 
   * 使用call方法,第一个参数为上下文; 
   * 有点类似Java中的super(name,age)的感觉 
   */ 
   Person.call(this, name, age); 
   this.no = no; 
  } 

  Student.prototype = new Person(); 

  var stu1 = new Student("0001","张三",11); 
  stu1.hobbies.push("soccer"); 
  stu1.say(); 

  var stu2 = new Student("0002","李四",12); 
  stu2.hobbies.push("cangjin"); 
  stu2.hobbies.push("basketball"); 
  stu2.say(); 
 </script>

输出:
0001 , 张三 , soccer  
0002 , 李四 , cangjin,basketball  
在Student的构造方法中使用了Person.call(this,name,age)感觉就像super(name,age)【call的第一个参数为上下文】;并且成功解决了对引用属性的共享问题,完美解决。

4、基于原型链的继承

<script type="text/javascript"> 

 /** 
  * 基于原型链的集成中都是对象 
  * 存在问题: 
  * 1、对于引用类型变量,造成数据不一致 
  */ 
 var Person = { 
    name: "人", 
    age: 0, 
    hobbies: [], 
    say: function () 
    { 
     console.log(this.name + " , " + this.age + " , " + this.hobbies); 
    } 
   } 
   ; 

 var Student = clone(Person); 
 Student.no =""; 
 Student.sayHello = function() 
 { 
  console.log(this.name +"hello ") ; 
 } 

 var stu1 = clone(Student); 
 stu1.name = "zhangsan"; 
 stu1.age = 12; 
 stu1.hobbies.push("Java"); 
 stu1.say(); 

 var stu2 = clone(Student); 
 stu2.name = "lisi"; 
 stu2.age = 13; 
 stu2.hobbies.push("Javascript"); 
 stu2.say(); 

 /** 
  * 返回一个prototype执行obj的一个对象 
  * @param obj 
  * @returns {F} 
  */ 
 function clone(obj) 
 { 
  var F = function () 
  { 
  }; 
  F.prototype = obj; 
  return new F(); 

 } 
</script>

输出:
zhangsan , 12 , Java  
lisi , 13 , Java,Javascript  
可以看出同样存在引用属性不一致的问题,并且整个操作全部基于对象,给人的感觉不是很好,下面通过图解解释下原理:

学习JavaScript设计模式(继承)

对象间通过一个clone函数,不断的返回一个新的对象,且prototype执行传入的对象,整个继承过程其实就是_proto_不断的指向,形成一个链,所以叫做原型链。

好了,已经介绍完了,js的两种集成的方式,最好使用的还是通过类的继承,比较稳定。

以上就是关于继承知识点的相关内容介绍,希望对大家的学习有所帮助。

Javascript 相关文章推荐
JSON+JavaScript处理JSON的简单例子
Mar 20 Javascript
js实现页面跳转重定向的几种方式
May 29 Javascript
Javascript 读取操作Sql中的Xml字段
Oct 09 Javascript
Bootstrap树形组件jqTree的简单封装
Jan 25 Javascript
基于javascript实现九九乘法表
Mar 27 Javascript
微信小程序 video组件详解
Oct 25 Javascript
jQuery插件HighCharts实现2D柱状图、折线图的组合多轴图效果示例【附demo源码下载】
Mar 09 Javascript
Vue2 Vue-cli中使用Typescript的配置详解
Jul 24 Javascript
vue根据进入的路由进行原路返回的方法
Sep 26 Javascript
ES10的13个新特性示例(小结)
Sep 23 Javascript
基于jQuery实现可编辑的表格
Dec 11 jQuery
详解node和ES6的模块导出与导入
Feb 19 Javascript
js图片跟随鼠标移动代码
Nov 26 #Javascript
学习JavaScript设计模式(封装)
Nov 26 #Javascript
JS实现密码框根据焦点的获取与失去控制文字的消失与显示效果
Nov 26 #Javascript
学习JavaScript设计模式(接口)
Nov 26 #Javascript
Jquery中request和request.form和request.querystring的区别
Nov 26 #Javascript
Jquery检验手机号是否符合规则并根据手机号检测结果将提交按钮设为不同状态
Nov 26 #Javascript
JS延时提示框实现方法详解
Nov 26 #Javascript
You might like
神盾加密解密教程(二)PHP 神盾解密
2014/06/08 PHP
PHP序列化和反序列化深度剖析实例讲解
2020/12/29 PHP
父子窗体间传递JSON格式的数据的代码
2010/12/25 Javascript
灵活应用js调试技巧解决样式问题的步骤分享
2012/03/15 Javascript
node.js开发中使用Node Supervisor实现监测文件修改并自动重启应用
2014/11/04 Javascript
教你如何使用node.js制作代理服务器
2014/11/26 Javascript
JS+CSS实现带关闭按钮DIV弹出窗口的方法
2015/02/27 Javascript
jQuery循环遍历子节点并获取值的方法
2016/04/14 Javascript
vue2.0+webpack环境的构造过程
2016/11/08 Javascript
原生JS实现图片轮播切换效果
2016/12/15 Javascript
200行代码实现blockchain 区块链实例详解
2018/03/14 Javascript
vue 点击按钮增加一行的方法
2018/09/07 Javascript
Electron 调用命令行(cmd)
2019/09/23 Javascript
Nodejs在局域网配置https访问的实现方法
2020/10/17 NodeJs
动态实现element ui的el-table某列数据不同样式的示例
2021/01/22 Javascript
[00:35]DOTA2上海特级锦标赛 VP战队宣传片
2016/03/04 DOTA
[54:29]2018DOTA2亚洲邀请赛 4.7 淘汰赛 VP vs LGD 第二场
2018/04/09 DOTA
Python base64编码解码实例
2015/06/21 Python
python实现多线程的方式及多条命令并发执行
2016/06/07 Python
Python多继承顺序实例分析
2018/05/26 Python
将Django项目部署到CentOs服务器中
2018/10/18 Python
django框架基于模板 生成 excel(xls) 文件操作示例
2019/06/19 Python
复化梯形求积分实例——用Python进行数值计算
2019/11/20 Python
python实现两个字典合并,两个list合并
2019/12/02 Python
python基于三阶贝塞尔曲线的数据平滑算法
2019/12/27 Python
Python解析多帧dicom数据详解
2020/01/13 Python
Python多重继承之菱形继承的实例详解
2020/02/12 Python
HTML5+CSS3:3D展示商品信息示例
2017/01/03 HTML / CSS
毕业生毕业总结的自我评价范文
2013/11/02 职场文书
大学生职业生涯规划大赛作品(精品)
2014/09/17 职场文书
党支部班子“四风”问题自我剖析材料
2014/09/28 职场文书
2014年党的群众路线整改措施思想汇报
2014/10/12 职场文书
人事主管岗位职责
2015/02/04 职场文书
销售辞职信范文
2015/03/02 职场文书
学校2015年纠风工作总结
2015/05/15 职场文书
Java 超详细讲解数据结构中的堆的应用
2022/04/02 Java/Android