学习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 相关文章推荐
等待指定时间后自动跳转或关闭当前页面的js代码
Jul 09 Javascript
Javascript 读取操作Sql中的Xml字段
Oct 09 Javascript
jQuery中animate动画第二次点击事件没反应
May 07 Javascript
JavaScript使表单中的内容显示在屏幕上的方法
Jun 29 Javascript
js淡入淡出焦点图幻灯片效果代码分享
Sep 08 Javascript
在WordPress中加入Google搜索功能的简单步骤讲解
Jan 04 Javascript
javascript cookie基础应用之记录用户名的方法
Sep 20 Javascript
常用的javascript设计模式
Jan 11 Javascript
jQuery中过滤器的基本用法示例
Oct 11 jQuery
实现jquery放大镜的两种方法
Feb 22 jQuery
在Create React App中使用CSS Modules的方法示例
Jan 15 Javascript
vue使用v-model进行跨组件绑定的基本实现方法
Apr 28 Vue.js
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 str_pad() 将字符串填充成指定长度的字符串
2010/02/23 PHP
PHP中__FILE__、dirname与basename用法实例分析
2014/12/01 PHP
php 解析xml 的四种方法详细介绍
2016/10/26 PHP
Laravel框架实现修改登录和注册接口数据返回格式的方法
2018/08/17 PHP
jsonp跨域请求数据实现手机号码查询实例分析
2015/12/12 Javascript
BootStrap智能表单实战系列(四)表单布局介绍
2016/06/13 Javascript
JavaScript暂停和继续定时器的实现方法
2016/07/18 Javascript
BootStrap中按钮点击后被禁用按钮的最佳实现方法
2016/09/23 Javascript
js判断iframe中元素是否存在的实现代码
2016/12/24 Javascript
Bootstrap模态窗口源码解析
2017/02/08 Javascript
老生常谈Bootstrap媒体对象
2017/07/06 Javascript
理解 Node.js 事件驱动机制的原理
2017/08/16 Javascript
Angular中封装fancyBox(图片预览)遇到问题小结
2017/09/01 Javascript
React.Js添加与删除onScroll事件的方法详解
2017/11/03 Javascript
解决angularjs中同步执行http请求的方法
2018/08/13 Javascript
Python中最常用的操作列表的几种方法归纳
2015/04/24 Python
Python随机读取文件实现实例
2017/05/25 Python
基于Python os模块常用命令介绍
2017/11/03 Python
python 爬虫一键爬取 淘宝天猫宝贝页面主图颜色图和详情图的教程
2018/05/22 Python
python爬虫简单的添加代理进行访问的实现代码
2019/04/04 Python
Python利用lxml模块爬取豆瓣读书排行榜的方法与分析
2019/04/15 Python
浅谈Python小波分析库Pywavelets的一点使用心得
2019/07/09 Python
程序员的七夕用30行代码让Python化身表白神器
2019/08/07 Python
python装饰器原理与用法深入详解
2019/12/19 Python
python爬虫今日热榜数据到txt文件的源码
2021/02/23 Python
大学生专科学习生活的自我评价
2013/12/07 职场文书
手术室护士长竞聘书
2014/03/31 职场文书
房产代理公证处委托书
2014/04/04 职场文书
领导工作表现评语
2015/01/04 职场文书
会议通知
2015/04/15 职场文书
电影雨中的树观后感
2015/06/15 职场文书
《给予树》教学反思
2016/03/03 职场文书
浅谈Python从全局与局部变量到装饰器的相关知识
2021/06/21 Python
MySQL系列之十 MySQL事务隔离实现并发控制
2021/07/02 MySQL
python基础之错误和异常处理
2021/10/24 Python
Vue elementUI表单嵌套表格并对每行进行校验详解
2022/02/18 Vue.js