学习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 相关文章推荐
javascript实现的listview效果
Apr 28 Javascript
一组JS创建和操作表格的函数集合
May 07 Javascript
javascript 设计模式之单体模式 面向对象学习基础
Apr 18 Javascript
一个可拖拽列宽表格实例演示
Nov 26 Javascript
jQuery判断对象是否存在的方法
Feb 05 Javascript
javascript判断网页是关闭还是刷新
Sep 12 Javascript
angularjs 表单密码验证自定义指令实现代码
Oct 27 Javascript
浅谈js原生拖放
Nov 21 Javascript
Angular2下使用pdf插件的方法详解
Apr 29 Javascript
在Layui 的表格模板中,实现layer父页面和子页面传值交互的方法
Sep 10 Javascript
浅析微信小程序modal弹窗关闭默认会执行cancel问题
Oct 14 Javascript
微信小程序 自定义弹窗实现过程(附代码)
Dec 05 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新手NOTICE错误常见解决方法
2011/12/07 PHP
PHP将整个网站生成HTML纯静态网页的方法总结
2012/02/05 PHP
php 注册时输入信息验证器的实现详解
2013/07/05 PHP
php+mysql不用递归实现的无限级分类实例(非递归)
2014/07/08 PHP
PHP生成推广海报的方法分享
2018/04/22 PHP
centos7上编译安装php7以php-fpm方式连接apache
2018/11/08 PHP
PHP var关键字相关原理及使用实例解析
2020/07/11 PHP
phpwind放自动注册方法
2006/12/02 Javascript
在IE上直接编辑网页内容的js代码(IE地址栏js)
2009/04/27 Javascript
jquery中实现标签切换效果的代码
2011/03/01 Javascript
Array栈方法和队列方法的特点说明
2014/01/24 Javascript
把jQuery的类、插件封装成seajs的模块的方法
2014/03/12 Javascript
nodejs的压缩文件模块archiver用法示例
2017/01/18 NodeJs
如何使用vuejs实现更好的Form validation?
2017/04/07 Javascript
各种选择框jQuery的选中方法(实例讲解)
2017/06/27 jQuery
详解HTTPS 的原理和 NodeJS 的实现
2017/07/04 NodeJs
基于iScroll实现下拉刷新和上滑加载效果
2017/07/18 Javascript
JavaScript函数绑定用法实例分析
2017/11/14 Javascript
angularjs中$http异步上传Excel文件方法
2018/02/23 Javascript
解析原来浏览器原生支持JS Base64编码解码
2019/08/12 Javascript
es6中reduce的基本使用方法
2019/09/10 Javascript
JavaScript和TypeScript中的void的具体使用
2019/09/12 Javascript
Ant Design Pro 之 ProTable使用操作
2020/10/31 Javascript
[03:26]《DAC最前线》之EG经理自述DOTA2经历
2015/02/02 DOTA
python3模拟百度登录并实现百度贴吧签到示例分享(百度贴吧自动签到)
2014/02/24 Python
Python编程中的文件读写及相关的文件对象方法讲解
2016/01/19 Python
Python的时间模块datetime详解
2017/04/17 Python
pandas 使用apply同时处理两列数据的方法
2018/04/20 Python
python实现Flappy Bird源码
2018/12/24 Python
对Django的restful用法详解(自带的增删改查)
2019/08/28 Python
详解css3 mask遮罩实现一些特效
2018/10/24 HTML / CSS
美国迪克体育用品商店:DICK’S Sporting Goods
2018/07/24 全球购物
两只小狮子教学反思
2014/02/05 职场文书
初级会计求职信范文
2014/02/15 职场文书
Python基础之操作MySQL数据库
2021/05/06 Python
MySQL如何使用使用Xtrabackup进行备份和恢复
2021/06/21 MySQL