学习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移动和复制dom节点实用DOM操作案例
Dec 17 Javascript
juery框架写的弹窗效果适合新手
Nov 27 Javascript
JS弹出对话框实现方法(三种方式)
Dec 18 Javascript
jQuery+canvas实现简单的球体斜抛及颜色动态变换效果
Jan 28 Javascript
JS实现的几个常用算法
Nov 12 Javascript
JS实现键值对遍历json数组功能示例
May 30 Javascript
JavaScript中call和apply方法的区别实例分析
Aug 03 Javascript
three.js实现圆柱体
Dec 30 Javascript
Element-ui自定义table表头、修改列标题样式、添加tooltip、:render-header使用
Apr 11 Javascript
layui异步加载table表中某一列数据的例子
Sep 16 Javascript
JavaScript实现简单随机点名器
Nov 21 Javascript
js+canvas实现简单扫雷小游戏
Jan 22 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
IIS下配置Php+Mysql+zend的图文教程
2006/12/08 PHP
php json与xml序列化/反序列化
2013/10/28 PHP
PHP对接微信公众平台消息接口开发流程教程
2014/03/25 PHP
CodeIgniter基于Email类发邮件的方法
2016/03/29 PHP
Thinkphp 5.0实现微信企业付款到零钱
2018/09/30 PHP
向fckeditor编辑器插入指定代码的方法
2007/05/25 Javascript
jquery随意添加移除html的实现代码
2011/06/21 Javascript
JavaScript中setInterval的用法总结
2013/11/20 Javascript
javascript模拟实现ajax加载框实例
2014/10/15 Javascript
Nodejs极简入门教程(三):进程
2014/10/27 NodeJs
EasyUI中datagrid在ie下reload失败解决方案
2015/03/09 Javascript
基于jQuery Ajax实现上传文件
2016/03/24 Javascript
JS使用cookie设置样式的方法
2016/06/30 Javascript
JavaScript中定义对象原型的两种使用方法
2016/12/15 Javascript
Bootstrap源码解读导航条(7)
2016/12/23 Javascript
jQueryUI Sortable 应用Demo(分享)
2017/09/07 jQuery
解决ng-repeat产生的ng-model中取不到值的问题
2018/10/02 Javascript
webpack中如何使用雪碧图的示例代码
2018/11/11 Javascript
小试小程序云开发(小结)
2019/06/06 Javascript
原生js实现ajax请求和JSONP跨域请求操作示例
2020/03/14 Javascript
基于原生js实现九宫格算法代码实例
2020/07/03 Javascript
three.js 利用uv和ThreeBSP制作一个快递柜功能
2020/08/18 Javascript
python算法学习之基数排序实例
2013/12/18 Python
python版本坑:md5例子(python2与python3中md5区别)
2017/06/20 Python
Python实现计算圆周率π的值到任意位的方法示例
2018/05/08 Python
python numpy和list查询其中某个数的个数及定位方法
2018/06/27 Python
python正则表达式匹配不包含某几个字符的字符串方法
2019/07/23 Python
Python实现bilibili时间长度查询的示例代码
2020/01/14 Python
使用Filters滤镜弥补CSS3的跨浏览器问题以及兼容低版本IE
2013/01/23 HTML / CSS
Mankind西班牙男士护肤品网站:购买皮肤护理、护发和剃须
2017/04/27 全球购物
Giuseppe Zanotti美国官方网站:将鞋履视为高级时装般精心制作
2018/02/06 全球购物
苏格兰在线威士忌商店:The Whisky Barrel
2019/05/07 全球购物
C语言中break与continue的区别
2012/07/12 面试题
工作说明书格式
2014/07/29 职场文书
二手车转让协议书
2015/01/29 职场文书
宝宝满月宴答谢词
2015/09/30 职场文书