JavaScript有多种继承模式,总结起来用到的方法有:原型链的传递、构造函数的借用、对象的复制。

 
 

这篇文章讲得很清晰,让我们明白:所有JS对象源于null,并通过原型指针和原型对象来实现继承。

构造函数和原型对象的关系如下:

 
 

每个构造函数都有一个prototype属性,指向函数的原型对象;原型对象中又有一个constructor属性,重新指向构造函数。而对象实例中有一个原型指针[[prototype]](在Firefox、Safari和Chrome中,对应属性proto),指向原型对象。
明白原型之后,就进入正题继承了。

1.原型链继承

function SuperType(){
this.superproperty = true;
}
SuperType.prototype.getSuperValue = function(){
return this.superproperty;
}
function SubType(){
this.subproperty = false;
}
SubType.prototype = new SuperType(); //原型链继承
SubType.prototype.getSubValue =function(){
return this.subproperty;
}
var instance = new SubType();
alert(instance.getSuperValue());//true
 
 

通过SubType.prototype=new SuperType(),实现了以下三点:
A:重写了SubType的原型,让子类原型和子类构造函数之间断开联系。
B:子类原型是父类的实例,其原型指针[[prototype]]指向了父类的原型对象,这样子类就可以沿着原型链访问到父类的方法getSuperValue()。
C:子类原型是父类实例,通过父类构造函数,子类原型继承了父类的属性superproperty。
最终,子类继承了父类的方法和属性。
原型链继承的问题:
父类的实例属性成了子类的原型属性,如上面的superproperty,会被子类所有实例共享。该属性是基本类型值时没有问题,但如果是引用类型值(比如数组),那么修改实例1的该属性(比如向数组push一个新值),实例2也会跟着改变。
也就是说,实例们只有共性,不能保持个性。

2.构造函数继承

function SuperType(name){
this.name = name;
}
function SubType(){
//继承了SuperType,同时还传递了参数
SuperType.call(this,"Nicholas");
this.age = 29;
}
var instance = new SubType();
alert(instance.name); //"Nicholas"
alert(instance.age); //29
 
 

通过SuperType.call(this),在子类构造函数中调用了父类的构造函数,创建子类实例会执行子类的构造函数(含父类的构造函数),也就完成了继承。当然,子类和父类的原型是没有关系的,子类实例不能访问父类原型对象中的属性和方法。
构造函数继承的问题:
方法在构造函数中定义,无法实现函数复用。比如父类中有一个方法getName(),则每次创建子类实例的时候,都要创建一个新的getName(),通过instance1.getName() !== instance.getName()就可以验证这一点。
这就是说,实例们保持了个性,却不能共享方法。

3.组合继承

function SuperType(name){
this.name = name;
this.colors = ["red","blue","green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
}
function SubType(name,age){
//继承属性
SuperType.call(this,name); //第二次调用SuperTyper()
this.age = age;
}
//继承方法
SubType.prototype = new SuperType(); //第一次调用SuperTyper()
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
alert(this.age);
} var instance1 = new SubType("Nicholas",29);
instance1.colors.push("black");
alert(instance1.colors); // "red","blue","green","black"
instance1.sayName(); //"Nicholas"
instance1.sayAge(); //29 var instance2 = new SubType("Greg",27);
alert(instance2.colors); // "red","blue","green"
instance2.sayName(); //"Greg"
instance2.sayAge(); //27
 
 

通过借用构造函数来继承属性,原型链来继承方法。结合了两者的优点,让实例们即保持个性,又共享方法。
组合继承的问题:
两次调用父类的构造函数。第一次(A):SubType.prototype=new SuperType(),子类原型对象取得了父类的实例属性。第二次(B):
SuperType.call(this),创建子类实例时,调用父类构造函数,重写实例属性,屏蔽了原型对象上同名属性。

4.原型式继承

function object(o){
function F(){};
F.prototype = o;
return new F();
}
var person = {
name:"Nicholas",
friends:["Shelby","Court","Van"]
}; var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob"); var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie"); alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"
 
 

以一个对象为基础,通过object()函数进行浅复制,再将得到的对象实例加以修改。
可以看到,这种继承方法是没有父类和子类的,只是通过复制对象来得到副本。
ES5有object.create()方法,是object()的规范化,可以传入两个参数:要复制的对象和额外的属性对象(如{name:{value:Greg}},这种方式会覆盖基础对象上的同名属性)。
原型式继承的问题:
和原型链继承一样,继承的属性由所有实例共享,改动一个实例的引用类型值时,所有实例都会改变。

5.寄生式继承

function createAnother(original){
var clone = object(original);//object()函数创建对象
clone.sayHi = function(){ //增强这个对象
alert("hi");
};
return clone; //返回这个对象
}
var person = {
name:"Nicholas";
friends:["Shelby","Court","Van"];
} //基础对象
var anotherPerson = createAnother(person); //新对象
anotherPerson.sayHi(); //"hi"

寄生式和原型式方法相同,都是复制一个基础对象来得到新对象,不同的是它将对象实例的修改放到也放到函数中,将整个过程(创建、增强、返回)封装了起来。

6.寄生组合式继承

function inheritPrototype(subType,superType){
var prototype = object(superType.prototype); //创建对象
prototype.constructor = subType; //增强对象
subType.prototype = prototype; //指定对象
}
function SuperType(name){
this.name = name;
this.colors = ["red","blue","green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
}
function SubType(name,age){
//继承属性
SuperType.call(this,name); //只调用一次SuperTyper()
this.age = age;
}
//继承方法
inheritPrototype(SubType,SuperType);
SubType.prototype.sayAge = function(){
alert(this.age);
}
 
 

顾名思义,这种继承模式就是寄生式(复制)+组合式(原型链+构造函数),将几种方法组合起来。解决了组合式继承两次调用父类构造函数的问题。

JavaScrip继承图文总结的更多相关文章

  1. 明白JavaScript原型链和JavaScrip继承

    原型链是JavaScript的基础性内容之一.其本质是JavaScript内部的设计逻辑. 首先看一组代码: <script type="text/javascript"&g ...

  2. 图文例解C++类的多重继承与虚拟继承

    文章导读:C++允许为一个派生类指定多个基类,这样的继承结构被称做多重继承. 在过去的学习中,我们始终接触的单个类的继承,但是在现实生活中,一些新事物往往会拥有两个或者两个以上事物的属性,为了解决这个 ...

  3. 读jQuery源码之整体框架分析

    读一个开源框架,大家最想学到的就是设计的思想和实现的技巧.最近读jQuery源码,记下我对大师作品的理解和心得,跟大家分享,权当抛砖引玉. 先附上jQuery的代码结构. (function(){ / ...

  4. 《挑战30天C++入门极限》图文例解C++类的多重继承与虚拟继承

        图文例解C++类的多重继承与虚拟继承 在过去的学习中,我们始终接触的单个类的继承,但是在现实生活中,一些新事物往往会拥有两个或者两个以上事物的属性,为了解决这个问题,C++引入了多重继承的概念 ...

  5. 「万字图文」史上最姨母级Java继承详解

    摘要:继承是面向对象软件技术中的一个概念.它使得复用以前的代码非常容易,能够大大缩短开发周期,降低开发费用. 本文分享自华为云社区<「万字图文」史上最姨母级Java继承详解丨[奔跑吧!JAVA] ...

  6. JavaScrip之对象与继承

    这章主要学习对象.原型.原型链和继承,比较核心,所以单独整理这一章的内容. 理解对象:一组名值对,值可以是数据或函数. 属性类型:1数据属性:包含一个数据值的位置.在这个位置可以读取和写入值,4个描述 ...

  7. Android中ListView实现图文并列并且自定义分割线(完善仿微信APP)

    昨天的(今天凌晨)的博文<Android中Fragment和ViewPager那点事儿>中,我们通过使用Fragment和ViewPager模仿实现了微信的布局框架.今天我们来通过使用Li ...

  8. C#开发微信门户及应用(19)-微信企业号的消息发送(文本、图片、文件、语音、视频、图文消息等)

    我们知道,企业号主要是面向企业需求而生的,因此内部消息的交流显得非常重要,而且发送.回复消息数量应该很可观,对于大企业尤其如此,因此可以结合企业号实现内部消息的交流.企业号具有关注安全.消息无限制等特 ...

  9. C#开发微信门户及应用(3)--文本消息和图文消息的应答

    微信应用如火如荼,很多公司都希望搭上信息快车,这个是一个商机,也是一个技术的方向,因此,有空研究下.学习下微信的相关开发,也就成为计划的安排事情之一了.本系列文章希望从一个循序渐进的角度上,全面介绍微 ...

随机推荐

  1. Delphi使用逍遥安卓模拟器

    由于使用红鱼儿推荐的iTools安卓模拟器一打开virtualbox就消失,所以自己琢磨了使用逍遥安卓 首先在软件管理里面下载逍遥安卓,然后安装设置一下: 3.安装并启动虚拟机,Delphi IDE是 ...

  2. svg旋转动画

    <!doctype html><html><head> <title>test</title> <meta charset=" ...

  3. springboot整合websocket实现一对一消息推送和广播消息推送

    maven依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...

  4. cdnbest如何查看节点和站点的流量,负载和连接信息

    1. 通过查看top信息,查看该区域下所有节点和有访问量的站点的负载情况 点节点列表==>top图标 2. 查看单台节点的负载和连接信息 点节点列表==>管理 点击下图中三个红框可以查看单 ...

  5. “AS3.0高级动画编程”学习:第四章 寻路(AStar/A星/A*)算法 (下)

    在前一部分的最后,我们给出了一个寻路的示例,在大多数情况下,运行还算良好,但是有一个小问题,如下图: 很明显,障碍物已经把路堵死了,但是小球仍然穿过对角线跑了出来! 问题在哪里:我们先回顾一下ASta ...

  6. Sping Cloud hystrix.stream 自动发现-监控

    相关组件安装脚本 [root@java_gateway4 java_tps]# cat cront_install.sh #!/bin/bashyum install jq -ymkdir /home ...

  7. flutter 自己整理

    2018-05 资料 常见问题解决处 https://flutter.io/flutter-for-android/ 起步 api widget https://flutter.io/docs/ 其他 ...

  8. [leetcode]98. Validate Binary Search Tree验证二叉搜索树

    Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as ...

  9. 浅谈js抽象工厂模式

    一.简单工厂 定义:简单工厂模式中,可以根据参数的不同返回不同类的实例.简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类. 比如你去专门卖鼠标的地方你可以买各种各样的 ...

  10. 异常解决 Unable to write generated Java files for schemas: null

    错误是在使用cxf调用其他系统接口时报出的.而且问题很诡异,只有服务器调用时才报错,本地直接写main方法直接调用却正常的.以下是异常的堆栈: ERROR c.k.p.webservice.WebSe ...