zoukankan      html  css  js  c++  java
  • JS 实现继承的几种方式

    继承的目的简单讲就是要使用父类的实例属性或原型属性

    // 父类
    function Animal(name, color) {
        // 实例属性
        this.name = name;
        this.color = color;
    }
    // 原型属性
    Animal.prototype.getName = function() {
        return this.name;
    }
    // 子类
    function Cat() {
        xxxxxx
    }
    
    

    构造函数继承

    原理:在子类的构造函数中调用父类的构造函数

    function Cat(name, color) {
        // 调用了父类的构造函数,将其中的this指向了子类的实例
        Animal.call(this, name, color);
        this.xxx = xxx;
    }
    

    优点:可以向父类构造函数传参
    缺点:只能继承父类的实例属性

    原型链继承 之 间接原型继承

    原理:将子类原型指向父类的实例

    Cat.prototype = new Animal()
    Cat.prototype.constructor = Cat;
    

    优点:

    1. 子类原型的修改不会影响到父类原型
    2. 既能继承实例属性,也能继承原型属性

    缺点:

    1. 不方便给父类的构造函数传参,传也只是一次性的,只能在刚开始修改子类原型的时候传
    2. 子类的原型是父类的实例,继承自父类实例上的属性对子类实例来说是公有的

    注意:给子类添加原型方法一定要在 Cat.prototype = new Animal() 之后

    原型链继承 之 直接原型继承

    原理:将子类的原型指向父类的原型

    // 这种做法比较激进,弊端很大
    Cat.prototype = Animal.prototype;
    Cat.prototype.constructor = Cat;
    

    优点:貌似没有什么优点,不推荐使用
    缺点:

    1. 子类没有自己的原型,就没有自己的公共方法
    2. 修改子类的原型会影响到父类原型,即以后不能再给子类添加原型属性
    3. 只能继承父类的原型属性

    原型继承 之 使用空对象作为媒介

    原理:emmmm,看代码

    function extend(Parent) {
        function F(){}
        F.prototype = Parent.prototype;
        return new F();
    }
    Cat.prototype = extend(Animal);
    // 或者 Cat.prototype = Object.create(Animal.prototype);
    Cat.prototype.constructor = Cat;
    

    优点:

    1. 和直接原型继承相比,修改子类的原型不会影响到父类
    2. 和间接原型继承相比,子类的原型是一个空对象,内存占用较少(当然后期也可以加原型属性)

    缺点:只能继承原型属性

    拷贝继承

    原理:通过 for-in 将父类上的原型属性复制到子类原型

    function extend(Child, Parent) {
        var c = Child.prototype;
        var p = Child.prototype;
        for(var key in p) {
            if(!p.hasProperty(key)) return;
            c[key] = p[key];
        }
    }
    

    优点:emmmm...子类在继承前或继承后都可以设置原型属性
    缺点:只能继承父类的原型属性,性能较差?

    实际上也可以复制父类的实例,从而继承父类的实例属性,不过缺点和间接原型继承一样,父类实例的实例属性被子类实例共享。

    组合继承

    原理:构造函数继承 + 间接原型继承

    优点:既能继承实例属性,又能继承原型属性

    缺点:

    1. 间接原型继承的缺点:父类实例的实例属性被子类实例共享
    2. 调用了两次父类的构造函数,生成了两个父类实例,开销大 ----- 这里我不这么认为,我觉得使用call来调用父类构造函数并不是new调用,而是把父类的构造函数当成普通函数执行,仅仅是把this指向了子类的实例,执行父类构造函数仅仅是给子类实例添加私有属性,并不会创建父类实例。

    寄生组合式继承(推荐)

    原理:构造函数继承 + 空对象媒介

    优点:和组合继承相比,这样就不会生成父类实例了,且子类原型是个空对象,开销较小。

    总结

    只继承实例属性

    1. 构造函数继承(能给父类构造函数灵活传参)

    只继承原型属性

    1. 直接原型继承(不推荐)
    2. 空对象媒介(开销小)
    3. 拷贝继承(也可拷贝父类实例)

    既继承实例属性,又继承原型属性

    1. 间接原型继承
    2. 组合继承(构造函数继承 + 间接原型继承)
    3. 寄生组合继承(构造函数继承 + 空对象媒介)
  • 相关阅读:
    代理与反向代理
    Spring Batch 远程分区和远程分块的区别
    XWIKI部署安装
    想写一些与技术无关的
    1104报表
    ARQC与ARPC的生成和校验方法
    学习开源框架的一些总结
    linux java -version 和 javac -version 不一致
    spring boot 概念
    Unable to open socket file: target process not responding or HotSpot VM not loaded
  • 原文地址:https://www.cnblogs.com/hueralin/p/12538878.html
Copyright © 2011-2022 走看看