对象继承

109 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天juejin.cn/post/712312…

继承的方式

  1. 原始对象继承
  2. 原型链继承
  3. 构造函数基础
  4. 组合继承(原型链和构造函数)
  5. 寄生组合继承

原始对象继承

  • 核心:通过new关键字继承js原生构造函数Object的属性方法
  • 语法: var obj=new Object();

原型链继承

核心:将父类的实例作为子类的原型。

/ 把父类的实例对象作为子类的原型对象
    function Person(n,a){
        this.name=n;
        this.age=a;
        Person.prototype.sayName=function(){
            Alert(“使用原型得到name:”+this.name);
        }
    }
    function Aa(g){
        this.gard=g;
    }
    Aa.prototype=new Person("tom",20);//要把这一步放在构造器外面,否则访问不到属性值
    Aa.prototype.intr=function(){alert(this. gard)}//为子类新增方法,要放在new Person后面,并且不能放在构造器内。
    var b=new Aa("5年级");
    console.log(b.name)//通过原型链可访问到b继承来的name属性值
    console.log(b);
    b. sayName ();//输出:使用原型得到name:tom
    b.intr()//输出:5年级

原型链特点:

  1. 非常纯粹的继承关系,实例是子类的实例,也是父类的实例
  2. 父类新增原型方法,子类都能访问到
  3. 简单、易于实现

原型链缺点:

  1. 要想为子类新增属性和方法,必须要在new Person()这样的语句之后执行,不能放到构造器中
  2. 无法实现多继承(只能有一个子类)
  3. 来自原型对象的引用属性是所有实例共享的
  4. 创建子类实例时,无法向父类构造器传参

在解决原型中包含引用类型值所带来的问题,使用构造函数技术来解决。

构造函数继承

核心:使用父类的构造函数来增强子类实例,等于是复制父类的属性给子类(没有用到原型)

// 方法一
//创建一个构造函数父类
    function ClassA(sColor){
        this.color=sColor;
        this.sayColor=function(){
            alert(this.color)
        }
    }
   //子类
   function ClassB(bColor,bName){
        this.newMethod=ClassA; //把父类事例(函数名)作为子类的属性值      
        this.newMethod(bColor);//通过子类的实例对象调用父类构造函数,改变其中this的指向。
        delete this.newMethod;
        this.name=bName;
        this.sayName=function(){
           alert(this.name);
        }
   }
   var b=new ClassB("red","lily");
   console.log(b);
   b.sayName()
   b.sayColor()
   console.log(b.name)
   
   //方法二
    function Animal(name){
        this.name=name;
        this.showName=function(){
            alert(this.name)
        }
    }
    function Cat(name){
        Animal.call(this,name);//以前这里是把父类构造函数名作为子类的属性值,并进行调用
        //现在直接改变了showName里面this的指向
    }
    var cat=new Cat("Black Cat");
    cat.showName()
    console.log(cat)

构造继承特点:

  1. 解决了原型链继承中,子类实例共享父类引用属性的问题。
  2. 创建子类实例时,可以向父类传递参数
  3. 可以实现多继承(call多个父类对象) 缺点:
  4. 只能继承父类实例的属性和方法,不能继承原型属性/方法
  5. 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能。()
  6. 每次调用子类的时候,都会调用父类的方法。

组合继承

  • 组合继承,指的是将原型链和构造函数的技术组合到一起
  • 思路:是使用原型链实现对原型方法的继承,而通过借用构造函数来实现对实例属性的继承。
  • 这样,既通过在原型上定义方法实现了函数的复用,又能够保证每个实例都有它自己的属性。
// 2、又能够保证每个实例都有自己的属性
    function Person(n,a){
        this.name=n;
        this.age=a;
    }
    //1、通过在原型上定义方法实现复用
    Person.prototype.sayName=function(){
        alert(this.name)
    }
    function Student(sn,sa,g){
        Person.call(this,sn,sa)//改变了sayName方法里面this的指向,指向了当前构造函数里的this,这里也是对Person这个函数的调用,并把sn,sa这两个参数传了进去
        this.gard=g;
    }
    Student.prototype=new Person();//在这里又调用了一次Person这个构造函数,因为Student的原型是Person的实例,是个对象,对象没有construstor这个属性,所以再指回Student的原型里构造函数是Student自己本身
    Student.prototype.constructor=Student;//
    var s1=new Student("张三",20,3)
    console.log(s1)
    s1.sayName()
    var s2=new Student("李四",18)
    s2.sayName()
    console.log(s1.name)//张三
    console.log(s2)

组合继承特点:

  1. 弥补了构造继承的缺点,可以继承实例的属性和方法,也可以继承原型属性和方法
  2. 既是子类的实例,也是父类的实例
  3. 不存在引用属性共享问题
  4. 可传参
  5. 函数可复用

缺点:无论在什么情况下,都会调用两次父类 构造函数,一次是在创建子类原型的时候,一次是在子类构造函数的内部(即改变指针的方向)

寄生组合继承

核心:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造函数的时候,就不会初始化两次实例方法/属性,避免了组合继承的缺点。

   // 核心:通过寄生方法,砍掉父类的实例属性,这样,在调用两次父类的构造的时候
   //就不会初始化两次实例方法/属性,避免了组合继承来的缺点
    // 混合模式  ——父类
    function Animal(name){
        this.name=name;
    }
    Animal.prototype.showName=function(){//Animal的原型里只有一个showName方法,没有任何属性
       alert(this.name)
    }
    // 构造函数  ——子类
    function Cat(number,name){
        Animal.call(this,name)
        this.num=number;
    }
    // 因为组合模式会调用两次Animal函数,而且不仅继承里面的方法,还有属性
    (function (){
        //创建一个没有实例方法的类
        var Super=function(){};
        Super.prototype=Animal.prototype;//这时候Super原型里也只有showName一个方法
        Cat.prototype=new Super();//Super实例里面也只有一个继承来的方法showName
    })();
    Cat.prototype.constructor=Cat;
    var cat=new Cat(10,"狗");
    cat.showName();
    alert(cat.num)
    console.log(cat)

寄生组合继承特点:只调用了一次supertype构造函数,因此避免在suptype.prototype上创建不必要的,多余的属性,与此同时,原型链还能保持不变,还能正常使用instancof和isPrototypeOf(),因此,寄生组合式继承被认为是引用类型最理想的继承方式。 缺点:实现较为复杂。