学习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 插件 人性化的消息显示
Jan 21 Javascript
JavaScript取得鼠标绝对位置程序代码介绍
Sep 16 Javascript
javascript 图片裁剪技巧解读
Nov 15 Javascript
javascript得到当前页的来路即前一页地址的方法
Feb 18 Javascript
基于JavaScript将表单序列化类型的数据转化成对象的处理(允许对象中包含对象)
Dec 28 Javascript
原生js实现焦点轮播图效果
Jan 12 Javascript
解决AjaxFileupload 上传时会出现连接重置的问题
Jul 07 Javascript
vue将毫秒数转化为正常日期格式的实例
Sep 16 Javascript
jQuery时间戳和日期相互转换操作示例
Dec 07 jQuery
微信小程序自定义导航教程(兼容各种手机)
Dec 12 Javascript
微信小程序实现元素渐入渐出动画效果封装方法
May 18 Javascript
vue学习笔记之作用域插槽实例分析
Feb 01 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入门速成(2)
2006/10/09 PHP
PHP 清空varnish 缓存的详解(包括指定站点下的)
2013/06/20 PHP
PHP格式化MYSQL返回float类型的方法
2016/03/30 PHP
PHP读取CSV大文件导入数据库的实例
2017/07/24 PHP
php集成开发环境详解
2019/09/24 PHP
JavaScript 常见对象类创建代码与优缺点分析
2009/12/07 Javascript
Function.prototype.call.apply结合用法分析示例
2013/07/03 Javascript
JavaScript instanceof 的使用方法示例介绍
2013/10/23 Javascript
jquery禁用右键示例
2014/04/28 Javascript
JavaScript实现点击单选按钮改变输入框中文本域内容的方法
2015/08/12 Javascript
JavaScript操作HTML元素和样式的方法详解
2015/10/21 Javascript
JavaScript的Backbone.js框架入门学习指引
2016/05/07 Javascript
Javascript 动态改变imput type属性
2016/11/01 Javascript
微信小程序之选项卡的实现方法
2017/09/29 Javascript
jQuery+CSS实现的table表格行列转置功能示例
2018/01/08 jQuery
JavaScript 隐性类型转换步骤浅析
2018/03/15 Javascript
Javascript获取某个月的天数
2018/05/30 Javascript
vue  自定义组件实现通讯录功能
2018/09/30 Javascript
JS大坑之19位数的Number型精度丢失问题详解
2019/04/22 Javascript
[45:25]完美世界DOTA2联赛循环赛 PXG vs IO 第一场 11.06
2020/11/09 DOTA
机器学习的框架偏向于Python的13个原因
2017/12/07 Python
Python实现全排列的打印
2018/08/18 Python
python 拼接文件路径的方法
2018/10/23 Python
Python中logging实例讲解
2019/01/17 Python
使用Python控制摄像头拍照并发邮件
2019/04/23 Python
pycharm 激活码及使用方式的详细教程
2020/05/12 Python
python 元组的使用方法
2020/06/09 Python
解决c++调用python中文乱码问题
2020/07/29 Python
matplotlib 三维图表绘制方法简介
2020/09/20 Python
印度尼西亚最大的电商平台:Tokopedia(印尼版淘宝)
2017/12/02 全球购物
我们是伦敦女孩:WalG
2018/01/08 全球购物
纽约海:Sea New York
2018/11/04 全球购物
C++:局部变量能否和全局变量重名
2014/03/03 面试题
小学班级口号大全
2015/12/25 职场文书
《好妈妈胜过好老师》:每个孩子的优秀都是有源头的
2020/01/03 职场文书
Go语言空白表示符_的实例用法
2021/07/04 Golang