学习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 相关文章推荐
解决用jquery load加载页面到div时,不执行页面js的问题
Feb 22 Javascript
jquery中attr和prop的区别分析
Mar 16 Javascript
Node.js的Express框架使用上手指南
Mar 12 Javascript
js实现统计字符串中特定字符出现个数的方法
Aug 02 Javascript
AngularJS表格详解及示例代码
Aug 17 Javascript
JavaScript仿百度图片浏览效果
Nov 23 Javascript
BootStrap表单控件之复选框checkbox和单选择按钮radio
May 23 Javascript
JavaScript上传文件时不用刷新页面方法总结(推荐)
Aug 15 Javascript
Vue2.0基于vue-cli+webpack父子组件通信(实例讲解)
Sep 14 Javascript
如何利用ES6进行Promise封装总结
Feb 11 Javascript
点击按钮弹出模态框的一系列操作代码实例
Mar 29 Javascript
html+jQuery实现拖动滑块图片拼图验证码插件【移动端适用】
Sep 10 jQuery
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
echo, print, printf 和 sprintf 区别
2006/12/06 PHP
php 动态执行带有参数的类方法
2009/04/10 PHP
PHP中对数组的一些常用的增、删、插操作函数总结
2015/11/27 PHP
PHP实现自动识别原编码并对字符串进行编码转换的方法
2016/07/13 PHP
php实现的http请求封装示例
2016/11/08 PHP
php删除txt文件指定行及按行读取txt文档数据的方法
2017/01/30 PHP
PHP实现类似于C语言的文件读取及解析功能
2017/09/01 PHP
jQuery 跨域访问问题解决方法
2009/12/02 Javascript
xheditor与validate插件冲突的解决方案
2010/04/15 Javascript
javascript中的if语句使用介绍
2013/11/20 Javascript
Bootstrap 组件之按钮(二)
2016/05/11 Javascript
关于JavaScript 原型链的一点个人理解
2016/07/31 Javascript
学习vue.js表单控件绑定操作
2016/12/05 Javascript
利用node.js搭建简单web服务器的方法教程
2017/02/20 Javascript
Vue表单demo v-model双向绑定问题
2018/06/29 Javascript
Vue动态路由缓存不相互影响的解决办法
2019/02/19 Javascript
浅谈express.js框架中间件(middleware)
2019/04/07 Javascript
浅谈Vue页面级缓存解决方案feb-alive(上)
2019/04/14 Javascript
vue路由跳转传递参数的方式总结
2020/05/10 Javascript
JavaScript 判断浏览器是否是IE
2021/02/19 Javascript
对python的文件内注释 help注释方法
2018/05/23 Python
python pyheatmap包绘制热力图
2018/11/09 Python
python利用thrift服务读取hbase数据的方法
2018/12/27 Python
命令行运行Python脚本时传入参数的三种方式详解
2019/10/11 Python
python子线程退出及线程退出控制的代码
2019/10/16 Python
python自动生成model文件过程详解
2019/11/02 Python
selenium+python实现自动登陆QQ邮箱并发送邮件功能
2019/12/13 Python
python实现PolynomialFeatures多项式的方法
2021/01/06 Python
优秀信贷员先进事迹
2014/01/31 职场文书
2014年音乐教师工作总结
2014/12/03 职场文书
辩论赛新闻稿
2015/07/17 职场文书
小学三年级语文教学反思
2016/03/03 职场文书
员工安全责任协议书
2016/03/22 职场文书
Python面向对象编程之类的概念
2021/11/01 Python
详解Python内置模块Collections
2022/03/22 Python
MySQL数据库中的锁、解锁以及删除事务
2022/05/06 MySQL