ECMAScript只支持实现继承(继承实际的方法),主要依靠原型链来实现。

1、原型链

基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。

示例:

  function SuperType(){
        this.property = true; //实例属性
    }
    SuperType.prototype.getSuperValue = function(){//原型方法
        return this.property;
    }

function SubType(){
        this.subproperty = false;
    }
    
    //SubType继承了SuperType
    SubType.prototype = new SuperType();
    
    SubType.prototype.getSubValue = function(){
        return this.subproperty;
    }
    
    var instance = new SubType();
    console.log(instance.getSuperValue()); //true
    console.log(instance.constructor); //SuperType

说明:

  以上代码创建了两个类型:SuperType 和 SubType。这两个类型都有各自的属性和方法,SubType继承了SuperType,继承是通过创建SuperType的实例,并把该实例赋给SubType的prototype。实现的本质是重写了SubType原型对象,代之以一个新类型的实例。

  SubType的新原型具有SuperType所有的属性和方法,同时其内部还有一个指针[[Prototype]],指向SuperType的原型,最终结果是instance指向了SubType的原型,SubType的原型又指向了SuperType的原型。

  instance.constructor指向的是SuperType,这是因为原来的SubType.prototype中的constructor被重写了。(实际上不是SubType的原型的constructor属性被重写了,而是SubType的原型指向了SuperType,而这个原型的constructor属性指向的是SuperType。)

  所有引用类型默认都继承了Object,这个继承也是通过原型链类实现的。所有函数的默认原型都是Object的实例,默认原型都会包含一个内部指针,指向Object.prototype。

注意:在通过原型链实现继承时,不能使用字面量对象创建原型方法,这样会重写原型链,把我们的原型链切断。

原型链的问题:(1)、包含引用类型值的原型;

(2)、创建子类型的实例时,不能向超类型的构造函数中传递参数。

2、借用构造函数

也叫伪造对象或者经典继承,基本思想是在子类型构造函数内部调用超类型构造函数。

function SuperType(name){
        this.name = name;
        this.colors = ['red', 'blue', 'green'];
    }
    
    function SubType(){
        //继承了SubType,同时还传递了参数
        SuperType.call(this, 'Nick');
        
        //实例属性
        this.age = 12;
    }
    
    var instance1 = new SubType();
    instance1.colors.push('gray');
    console.log(instance1.name);
    console.log(instance1.age);
    
    var instance2 = new SubType();
    console.log(instance2.colors);

借用构造函数的问题:方法都在构造函数中定义,因此函数复用就无从谈起了。而且,在超类型的原型中定义的方法,对子类型而言也是不可见的。

3、组合继承

也叫伪经典继承,基本思想是使用原型链实现对原型属性和方法的继承,通过借用构造函数实现对实例属性的继承,这样,即通过在原型上定义方法实现了函数复用,又能保证每个实例都有它自己的属性。

function SuperType(name){
        this.name = name;
        this.colors = ['red', 'yellow', 'blue'];
    }
    
    SuperType.prototype.sayName = function(){
        return this.name;
    }
    
    function SubType(name, age){
        //继承属性
        SuperType.call(this, name);
        this.age = age;
    }
    //继承方法
    SubType.prototype = new SuperType();
    
    SubType.prototype.sayAge = function(){
        return this.age;
    }
    
    var instance1 = new SubType('Tom', 12);
    instance1.colors.push('black');
    console.log(instance1.colors);//['red', 'yellow', 'blue', 'black']
    console.log(instance1.sayAge());//12
    console.log(instance1.sayName());//Tom
    
    var instance2 = new SubType('Lucy',21);
    console.log(instance2.colors);//['red', 'yellow', 'blue']
    console.log(SubType.prototype.isPrototypeOf(instance2));//true
    console.log(SuperType.prototype.isPrototypeOf(instance2));//true

组合继承是JavaScript常用的继承模式,但是也有不足。

4、寄生组合式继承

通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。

//借助原型基于已有对象创建新对象(本质上讲,object()对传入的对象执行了一次浅复制)
    function object(o){
        function F(){}
        F.prototype = o;
        return new F();
    }
    //使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型
    function inheritPrototype(SuperType, SubType){
        var prototype = object(SuperType.prototype);//创建超类型原型的一个副本
        prototype.constructor = SubType;//增强对象,弥补因重写原型而失去的默认的constructor属性
        SubType.prototype = prototype;
    }

function SuperType(name){
        this.name = name;
        this.colors = ['blue', 'red', 'green'];
    }
    
    SuperType.prototype.sayName = function(){
        return this.name;
    }
    
    function SubType(name, age){
        SuperType.call(this, name);
        this.age = age;
    }
    
    inheritPrototype(SuperType, SubType);
    
    SubType.prototype.sayAge = function(){
        return this.age;
    }
    
    var instance = new SubType('Tom', 12);
  instance.colors.push('black');
  console.log(instance.colors);
  delete instance.name;
  console.log(instance.name);

  var instance = new SubType('Lucy', 33);
  console.log(instance.colors);

普遍认为寄生组合式继承是引用类型最理想的继承范式。

js 继承的更多相关文章

  1. js继承

    js继承有5种实现方式: 继承第一种方式:对象冒充 function Parent(username){ this.username = username; this.hello = function ...

  2. js继承之call,apply和prototype随谈

    在js中,call,apply和prototype都可以实现对象的继承,下面我们看一个例子: function FatherObj1() { this.sayhello = "I am jo ...

  3. js继承精益求精之寄生式组合继承

    一.混合/组合继承的不足 上一篇JS继承终于混合继承,认真思考一下,发现其还是有不足之处的: 空间上的冗余:在使用原型链的方法继承父类的原型属性(Animal.prototype)的同时,也在子类的原 ...

  4. 老生常谈--Js继承小结

    一直以来,对Js的继承有所认识,但是认识不全面,没什么深刻印象.于是,经常性的浪费很多时间重新看博文学习继承,今天工作不是特别忙,有幸看到了http://www.slideshare.net/stoy ...

  5. Js继承小结

    Js继承小结 一直以来,对Js的继承有所认识,但是认识不全面,没什么深刻印象.于是,经常性的浪费很多时间重新看博文学习继承,今天工作不是特别忙,有幸看到了http://www.slideshare.n ...

  6. js继承实现

    JS实现继承可以分为:对象冒充和原型链继承 其中对象冒充又包括:临时变量,call 和 apply 临时变量方法: function Person(name,sex){ this.name = nam ...

  7. js继承之借用构造函数继承

    我的上一篇文章介绍了,原型链继承模式.但是单纯的原型链模式并不能很好地实现继承. 一.原型链的缺点 1.1 单纯的原型链继承最大的一个缺点,来自于原型中包含引用类型的值. 本来,我们没有通过原型链实现 ...

  8. js继承之原型链继承

    面向对象编程都会涉及到继承这个概念,JS中实现继承的方式主要是通过原型链的方法. 一.构造函数.原型与实例之间的关系 每创建一个函数,该函数就会自动带有一个 prototype 属性.该属性是个指针, ...

  9. js继承的常用方法

    写在前面的话:这篇博客不适合对面向对象一无所知的人,如果你连_proto_.prototype...都不是很了解的话,建议还是先去了解一下JavaScript面向对象的基础知识,毕竟胖子不是一口吃成的 ...

  10. JS--我发现,原来你是这样的JS:面向对象编程OOP[3]--(JS继承)

    一.面向对象编程(继承) 这篇博客是面向对象编程的第三篇,JS继承.继承顾名思义,就是获取父辈的各种"财产"(属性和方法). 怎么实现继承? 我们的JavaScript比较特别了, ...

随机推荐

  1. 【转】nginx+iis实现负载均衡

    最近在研究分布式系统架构方面的知识,包括负载均衡,数据库读写分离,分布式缓存redis等.本篇先从负载均衡服务架构入手,关于负载均衡百度百科的定义如下:负载均衡,英文名称为Load Balance,其 ...

  2. 基于MVC4+EasyUI的Web开发框架经验总结(13)--DataGrid控件实现自动适应宽带高度

    在默认情况下,EasyUI的DataGrid好像都没有具备自动宽度的适应功能,一般是指定像素宽度的,但是使用的人员计算机的屏幕分辨率可能不一样,因此导致有些地方显示太大或者太小,总是不能达到好的预期效 ...

  3. .NET Core 调用WCF 服务

    .NET Core 和ASP.NET Core 已经可以调用WCF 服务. 环境要求: VS2015 Update 2 +VS2015 Tooling + .NET Core SDK 下载地址: ht ...

  4. Inno Setup info

    Introduce:     Inno Setup is a free installer for Windows programs. First introduced in 1997, Inno S ...

  5. js定时器的使用(实例讲解)

    在javascritp中,有两个关于定时器的专用函数,分别为: 1.倒计定时器:timename=setTimeout("function();",delaytime);2.循环定 ...

  6. MongoVUE(MongoDB图像管理工具)

    介绍一款很不错的开源的MongoDB图形化管理工具:MongoVUE 下载地址:MongoVUE 1.6.9 破解版

  7. linux_shell_4_shell特性

    去年的这个时候,我曾经写过一些关于shell特性的文章,下面是第3篇:linux_shell_3_shell变量特性. 今天我们继续来学习一些关于 Linux shell的内容. [1]shell 在 ...

  8. redis持久化机制

    redis持久化 redis的数据存在内存中,所以存取性能好.但是存在内存中的数据存在一个问题,一旦机器重启,内存数据消失.为了解决这个问题,redis支持持久化.持久化就是为了解决内存数据丢失时恢复 ...

  9. mysql autocommit=OFF导致wordpress 建立数据库连接时出错

    今天安装wordpress完成后跳转到login页面时,出现建立数据库连接时出错.网上清一色的拷贝http://mt.sohu.com/20160917/n468547634.shtml的答案. 只能 ...

  10. go语言 类型:数组切片

    初看起来,数组切片就像一个指向数组的指针,实际上它拥有自己的数据结构,而不仅仅是个指针.数组切片的数据结构可以抽象为以下3个变量: 1.一个指向原生数组的指针: 2.数组切片中的元素个数: 3.数组切 ...