JavaScript常用的继承方式

JavaScript常用继承方式主要分为(7种):原型链继承、构造函数继承、组合继承、原型式继承、寄生式继承、寄生组合继承以及继承多个对象。

1:原型链继承(核心:将父类的实例作为子类的原型)

基本概念:重写原型对象,赋予一个新的对象的实例。基本思想就是让一个原型对象指向另一个父类的实例。

    function Super() {
        //基本数据类型
        this.text = 'Hello';
    }
    Super.prototype.getSuperText = function() {
        return this.text;
    }
    function Sub() {
    	this.subText = 'Word';
    }
    
    Sub.prototype = new Super();
    
    const instance = new Sub();
    console.log(instance);

特点:非常纯粹的继承关系,实例是子类的实例,也是父类的实例。父类新增原型方法或属性,子类都能访问到。

优点:简单易于操作

缺点:对引用类型数据操作会互相(多个实例之间)影响

    function Super() {
        //复杂对象,也就是引用类型
        this.value = [1, 2, 3, 4];
    }
    Super.prototype.getSuperValue = function() {
        return this.value;
    }
    function Sub() {
        this.subText = 'Word';
    }
    
    Sub.prototype = new Super();
    
    const instance1 = new Sub();
    const instance2 = new Sub();
    
    instance1.value.push(5);
    console.log(instance2.value);
    
    // (5) [1, 2, 3, 4, 5]

2:构造函数继承

    //定义构造函数
    function Super(){
        this.value = [1, 2, 3, 4];
    }
    //新增属性getSuperValue
    Super.prototype.getSuperValue = function() {
        return this.value;
    }
    //sub每次执行都要重新调用
    function Sub(){
        Super.call(this);
    }
    
    const instance1 = new Sub();
    instance1.value.push(5);
    console.log(instance1.value);
    // (5) [1, 2, 3, 4, 5]
    
    const instance2 = new Sub();
    console.log(instance2.value);
    // (4) [1, 2, 3, 4]

构造函数的特点:(对引用数据类型没有影响)上面的代码输出instance1是1,2,3,4,5,instance2是1,2,3,4。这是因为sub每次在执行时都是重新调用了一个super.call(),而且构造函数在构建对象的过程中,每次都是创建了一个新的object,因此每次调用sub都会执行一遍super,每次执行时都会有申请一个新的内存空间,所以得到的两个value值是不一样互不影响的。

缺点:在整个构造函数的基础过程中,上面的代码并没有使用proto和prototype的属性,没有使用的话那么原型链就没有接上。所以说,构造函数基础只能继承父类的实例属性和方法,不能继承原型链上的属性和方法

3:组合继承

通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用。

保留了构造函数继承与原型链继承的优点。但是执行了两次Person,属性重复了。

    function Person(name) {
        this.name = name;
        this.value = ["head", "body", "legs"];
    }
    Person.prototype.getName = function() {
        return this.name;
    };
    
    // 构造函数继承
    function Teacher(name, school){
        // 执行又一次Person
        Person.call(this, name);
        this.school = school;
    }
    
    // 原型链继承
    // 执行一次Person
    Teacher.prototype = new Person(); 
    const Eric = new Teacher("Eric",27);
    Eric.getName();
    // 输出:Eric
    
    
    
    // prototype构造器指回自己 
    Teacher.prototype.constructor = Teacher;
    
    Teacher.prototype.getSchool = function() {
        return this.school;
    };

特点:既可以继承实例属性和方法,也可以继承原型属性和方法。既是子类的实例也是父类的实例,不存在引用属性共享的问题。可以传参,函数可复用。

缺点:调用两次父类构造函数,生成了两份实例。

4:原型式继承

借助原型可以基于已有的对象创建新的对象,同时还不必因此创建自定义类型。

原理:(本质)利用一个空对象作为一个中介。

    const lakers = {
        name: "lakers",
        value: ["Micheal", "Wade", "Kobe"]
    };
    
    const lakers1 = Object.create(lakers);
    const lakers2 = Object.create(lakers);
    
    lakers1.value.push('Fish');
    console.log(lakers);

模拟Object.create()

object.create()原理:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了一个可以随意添增属性的实例或对象。

    Object.prototype.create = function(obj) {
        function Fun() {}
        Fun.prototype = obj;
        return new Fun();
    }

缺点有两点:第一点是无法传递参数,第二点是引用类型存在变量的污染。****

5:寄生式继承

寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数。

目的:在原型式继承的基础上,寄生增加了一些新的方法和属性。

它的特点同原型式继承一样,也是无法传递参数,而且引用的数据类型也容易存在样式污染。

Object.createNew()

    Object.prototype.createNew = function(obj){
        var newObj = Object.create(obj);
        //获取长度等于一个function
        newObj.getLength = function(){ ... };
        return newObj;
    }

6:寄生组合继承

目的:为了解决数据重复拷贝两遍的问题。

Super只执行一次。

    //定义Super构造函数
    function Super(name) {
      this.name = name;
      this.value = ["Hello", "Word"];
    }
    //在super的原型链添加一个getName
    Super.prototype.getName = function() {
      return this.name;
    };
    //定义Sub
    function Sub(name, age) {
      //调用构造函数继承
      Super.call(this, name);
      this.age = age;
    }
    
    let prototype = Object.create(Super.prototype);
    prototype.constructor = Sub;
    Sub.prototype = prototype;
    
    Sub.prototype.getAge = function(){
      return this.age;
    }
    
    const instance1 = new Sub("Eric", 23);
    const instance2 = new Sub("Vico", 23);
    instance1.value.push("!");
    instance2.value.push("!!");

7:继承多个对象

借助原型式继承Object.create拿到SuperClass,也就是父类,拿到父类的prototype之后把它赋给ClassOne,

再然后我们将ClassTwo的prototype使用一个Object.assign,一个对象的拷贝,把它拷贝到ClassOne里面来,

然后最后ClassOne.prototype.constructor等于ClassOne

也就是使用一个Class.assign把所有我们想要继承的父类的prototype全部组合到一起完成一个拷贝,之后再赋给对象。

    function 
    
    ClassOne.prototype = Object.create(SuperClass.prototype);
    
    Object.assign(ClassOne.prototype, ClassTwo.prototype);
    
    ClassOne.prototype.constructor = ClassOne;

转载于:https://my.oschina.net/u/4144971/blog/3077146

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值