在面向对象语言中继承分成两种:接口继承和实现继承。解释一下,接口继承只继承方法的签名,而实现继承则是继承实际的方法。但是ECMAScript中的函数没有签名所以无法进行接口继承,只能是实现实现继承。而实现继承通常是依赖与原型链的。

原型链继承

原型的概念已经在上一篇中说过了。还是来简单的回顾一下构造函数,原型和实例的关系:每个构造函数都有一个圆形对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。但是如果让一个构造函数的原型指针指向另一个对象。那么这时的原型对象将包含一个指向另一个的原型的指针,如果层层递进的话就形成了原型链。

  1. function SupType(){
  2. this.property=true;
  3. }
  4.  
  5. SupType.prototype.getSupValue=function(){
  6. return this.property;
  7. }
  8.  
  9. function SubType(){
  10. this.subproperty=false;
  11. }
  12.  
  13. SubType.prototype=new SupType();
  14.  
  15. SubType.prototype.getSubValue=function(){
  16. return this.subproperty;
  17. }
  18.  
  19. var instace=new SubType();
  20. alert(instace.getSupValue());

这就是上面代码的原型图解。可以看到SubType的Prototype是指向一个SuperType的实例。SubTypePrototype并没有所谓的构造函数。这就是原型链的继承。当然不要忘记SuperType也是继承Object的。

可以用两个方式来进行判断原型和实例之间的关系。第一中是 instanceof操作符。

  1. alert(instace instanceof Object);
  2. alert(instace instanceof SubType);
  3. alert(instace instanceof SupType);

返回为true则为实例是原型链中出现过的构造函数。

还有一种就是isPrototypeof()方法。

  1. alert(Object.prototype.isPrototypeOf(instace));
  2. alert(SubType.prototype.isPrototypeOf(instace));
  3. alert(SupType.prototype.isPrototypeOf(instace));

原型链和原型模式的构造函数有着一样的缺点,所有的引用值类型会被所有的实例所引用。而且不能给父类的构造函数传参数。所以就会借用构造函数的方法以组合的方法进行函数的继承。

借用构造函数的方式

其实这种原理十分简单就是在子类型的构造函数内部调超类型的构造函数。

  1. function SupType(){
  2. this.colors=["red","blue","green"];
  3. }
  4.  
  5. function SubType(){
  6. SupType.call(this);
  7. }
  8.  
  9. var instance1=new SubType();
  10.  
  11. instance1.colors.push("black");
  12. alert(instance1.colors);
  13.  
  14. var instance2=new SubType();
  15. alert(instance2.colors);

在上面的代码中,在instance1中new的时候this就是intance1,然后调用了父类SupType的构造函数,在this的属性上添加了colors的属性。然后返回给instance1。这样每个实例都有独立的colors属性。

组合继承

顾名思义就是将使用原型链和构造函数两种进行组合继承。

  1. function SupType(name){
  2. this.name=name;
  3. this.colors=["red","blue","green"];
  4. }
  5.  
  6. SubType.prototype.sayName=function(){
  7. alert(this.name);
  8. }
  9.  
  10. function SubType(name,age)
  11. {
  12. SupType.call(this,name);
  13. this.age=age;
  14. }
  15.  
  16. SubType.prototype=new SupType();
  17. SubType.prototype.constructor=SubType;
  18. SubType.prototype.sayAge=function(){
  19. alert(this.age);
  20. }

在上面的代码中,需要共享的就添加到父类的原型中如方法SayName,不需要共享的就添加到构造函数中。在子类的构造函数中会有调用父类的构造函数,而且能传入参数。进行参数的初始化。这是JavaScript中最常用的继承模式。

原型式继承

原型式继承的原理就是一个对象可以作为另一个对象的基础。前者就是父类,后者是子类。看代码

  1. //原型式继承
  2. function object(o)
  3. {
  4. function F(){}
  5. F.prototype=o;
  6. return new F;
  7. }
  8.  
  9. //定义一个实体
  10. var person={
  11. name:"shaoqi",
  12. friends:["ss","qq","rr"]
  13. }
  14.  
  15. //调用方法
  16. var anotherPerson=object(person);
  17. anotherPerson.name="G";
  18. anotherPerson.friends.push("qq");
  19.  
  20. var yetanotherPerson=object(person);
  21. yetanotherPerson.name="G22";
  22. yetanotherPerson.friends.push("qq22");
  23.  
  24. alert(person.friends)

person就是anotherPerson和yetanotherPerson的父类,其实就是将子类的原型指针指向父类.那这个和原型链继承的差别是什么呢?在原型链中给子类的prototype是通过父类对象实例化的。而原型式中直接就是已有的对象。目的是什么呢?再基于已有对象创建新对象,同时还不必因此创建自定义的类型。

再ECMAScript5中通过Object.Create()的方法规范化了。不过这个原型链继承有着相同的缺点,就是所有的实例公用这同一个属性。

寄生式继承

寄生式继承和原型式继承关系紧密。其实就是在函数的内部对对象进行增强。

  1. function createAnother(obj)
  2. {
  3. var clone=object(obj);
  4. clone.sayHi=function(){
  5. alert("Hi!");
  6. }
  7.  
  8. return clone;
  9. }

其实我也不知道这个寄生模式有什么用?有大神的话可以解释下 这个不就是原型式的继承然后再原型中添加自己定义的方法嘛。也有可能是为了下面这个模式。

寄生组合模式

其实在上面的组合模式也并不是完全没有确定。我们先回顾一下代码。

  1. function SupType(name){
  2. this.name=name;
  3. this.colors=["red","blue","green"];
  4. }
  5.  
  6. SubType.prototype.sayName=function(){
  7. alert(this.name);
  8. }
  9.  
  10. function SubType(name,age)
  11. {
  12. SupType.call(this,name);
  13. this.age=age;
  14. }
  15.  
  16. SubType.prototype=new SupType();
  17. SubType.prototype.constructor=SubType;
  18. SubType.prototype.sayAge=function(){
  19. alert(this.age);
  20. }

在上面两个加粗的代码对SuperType进行了两次调用。简单来说就是再实例上name和colors被创建了一遍,然后再对象的实例上这两个属性又被创建了一遍。还是看图说话吧。这个是拍书的。将就的看下。

然后再对象上创建的实例属性屏蔽了原型上的实例。然后如何解决呢,那就是在组合模式中添加寄生模式。

  1. function inheritPrototype(subType,SupType)
  2. {
  3. var prototype=Object(SupType.prototype);//创建对象
  4. prototype.constructor=subType;
  5. subType.prototype=prototype;
  6. }
  7.  
  8. function SupType(name){
  9. this.name=name;
  10. this.colors=["red","blue","green"];
  11. }
  12.  
  13. SubType.prototype.sayName=function(){
  14. alert(this.name);
  15. }
  16.  
  17. function SubType(name,age)
  18. {
  19. SupType.call(this,name);
  20. this.age=age;
  21. }
  22.  
  23. //SubType.prototype=new SupType();
  24. inheritPrototype(SubType,SupType);
  25. SubType.prototype.constructor=SubType;
  26. SubType.prototype.sayAge=function(){
  27. alert(this.age);
  28. }

注意加粗的代码。调用了inheritPrototype这个方法。这个方法做了什么呢,它代替了new SuperType()这段代码。他没有去new 实例化创建属性,他复制了一份SuperType的prototype,然后将construction的指针指向subType。这样的话再SubType的prototype拥有了SuperType的原型方法,然后实例会调用SupType.call(this,name); 实例也有了在构造函数中定义的属性。

函数的构造就先写到这里。写的不好多多批评。

js面向对象程序设计之继承的更多相关文章

  1. JS面向对象程序设计(OOP:Object Oriented Programming)

    你是如何理解编程语言中的面向对象的? 我们研究JS和使用JS编程本身就是基于面向对象的思想来开发的,JS中的一切内容都可以统称为要研究的“对象”,我们按照功能特点把所有内容划分成“几个大类,还可以基于 ...

  2. js面向对象--类式继承

    //待研究//类式继承 //js中模拟类式继承的3个函数 //简单的辅助函数,让你可以将新函数绑定到对象的 prototype 上 Function.prototype.method = functi ...

  3. 从零开始的全栈工程师——JS面向对象( 六大继承 )

    一.对象克隆 var obj = { name:'li', age:23 } var obj2 = obj; // 这不是对象克隆 只是把obj的内存地址给obj2 1.for in克隆(浅拷贝)  ...

  4. JavaScript 对象的原型扩展(JS面向对象中的继承)

    <script type="text/javascript"> function person(name, age) { this._name = name; this ...

  5. js面向对象程序设计之构造函数

    再上一篇的开头说了创建对象的两种方式,一种是Object构造函数的方式,一种是对象字面量的方法.但这些方式创建多个对象的时候都会产生大量的重复代码.经过技术的进步也演化出来许多的创建对象的模式.本章会 ...

  6. js面向对象程序设计之属性和对象

    写在博客之前的话,这是我这个刚毕业的菜鸟的第一篇博客.一口吃不成一个胖子,我也希望写的第一篇东西就让读的人醍醐灌顶.我会抱着怀疑的态度来看自己写的文章,如果有写错的地方,请大家不要被误导,如果有大神提 ...

  7. python程序设计——面向对象程序设计:继承

    继承是为代码复用和设计复用而设计的 在继承关系中,已有的.设计好的类称为父类或基类,新设计的类为子类或派生类 派生类可以继承父类的公有成员,但不能继承其私有成员 如果需要在派生类中调用基类的方法,可以 ...

  8. 【c++】面向对象程序设计之继承中的类作用域

    当存在继承关系时,派生类的作用域嵌套在其基类的作用域之内. 一个对象.引用或指针的静态类型决定了该对象的哪些成员是可见的.即使静态类型与动态类型可能不一致,但我们使用哪些成员仍然是由静态类型决定的.基 ...

  9. node.js面向对象实现(二)继承

    http://blog.sina.com.cn/s/blog_b5a53f2e0101nrdi.html 继承是面向对象中非常重要的一个概念,那么在Node.js中如何实现继承呢? node.js在u ...

随机推荐

  1. C#基础知识之SharpZipLib压缩解压的使用

    项目中使用 Velocity 将模板和生成的动态内容(HTML.XML等)合并保存到redis数据库中,考虑到压缩的文件容量会比较小,方便传输而且存储所使用的空间也会比较小,所以要压缩一下,读取的时候 ...

  2. 【hiho1044】状压dp1

    题目大意:给定一个长度为 N 的序列,每个位置有一个权值,现选出一些点,满足相邻的 M 个点中至多有 Q 个点被选择,求选出点权的最大值是多少. 题解:若没有相邻的限制,这道题类似于子集和问题,即:背 ...

  3. ZROI CSP-S失恋测(1)

    传送门 写在前面:为了保护正睿题目版权,这里不放题面,只写题解. "怎么大家一个暑假不见都变菜了啊."--蔡老板 A 考虑一个\(nk^2\)的dp,按\(w_i\)排序,则每个组 ...

  4. selenium定位

    https://www.cnblogs.com/programer-xinmu78/p/10881766.html https://www.cnblogs.com/eastonliu/p/908830 ...

  5. Python----公开课

    # 构造函数- 类在实例化的时候,执行一些基础性的初始化的工作- 使用特殊的名称和写法- 在实例化的时候自动执行- 是在实例化的时候第一个被执行的函数- ----------------------- ...

  6. 【GDOI2014模拟】服务器

    前言 直到比赛最后几分钟,才发现60%数据居然是一个水dp,结果没打完. 题目 我们需要将一个文件复制到n个服务器上,这些服务器的编号为S1, S2, -, Sn. 首先,我们可以选择一些服务器,直接 ...

  7. 8:Spring Boot中thymeleaf模板中使用 Shiro标签

    1,添加 pom.xml grade: compile('com.github.theborakompanioni:thymeleaf-extras-shiro:1.2.1') 2, Subject ...

  8. PHP 大文件上传进度条实现

    核心原理: 该项目核心就是文件分块上传.前后端要高度配合,需要双方约定好一些数据,才能完成大文件分块,我们在项目中要重点解决的以下问题. * 如何分片: * 如何合成一个文件: * 中断了从哪个分片开 ...

  9. [USACO2019JAN]Sleepy Cow Sorting题解

    拿到这个问题,我们从头开始思考. 我们把序列看做两部分,一部分在前表示待排序的,记为序列1,一部分在后表示已排序的,记为序列2. 因为序列2在后,所以不必担心它影响序列1的排序,那么对于序列1的第一个 ...

  10. 解决:@Auarowired为null

    使用@Auarowired时程序报空指针.如图: 将private 更改为 public 即可