面向对象的程序设计——实现继承

借用构造函数

原理

在子类型构造函数的内部调用超类型构造函数

例如

        function SuperType() {
            this.colors=["red","blue","white"];
        }
        function SubType() {
            //继承了SuperType
            SuperType.call(this);
        }
        var instance1 = new SubType();
        instance1.colors.push("black");
        var instance2= new SubType();
        console.log(instance1.colors);
        console.log(instance2.colors);

结果
这里写图片描述

优点

可以在子类型构造函数中向超类型构造函数传递参数

例如

   function SuperType(name) {
            this.name = name;
        }
        function SubType() {
            //继承了SuperType
            SuperType.call(this,"Mike");
            this.age = 20;
        }
       var instance = new SubType();
        console.log(instance.name);
        console.log(instance.age);

结果
这里写图片描述

问题

1.方法在构造函数中定义,函数无法复用

2.在超类型定义的原型中定义的方法,对于子类型是不可见的,结果所有类型只能使用构造函数模式

组合继承

原理

将原型链和借用构造函数组合一起,使用原型链实现对原型链实现对原型属性和方法的继承,通过借用构造函数实现对实例属性的继承

优点

1.避免了原型链和借用构造函数的缺陷,融合了它们的优点,是JavaScript中最常见的继承模式

2.instanceof和isPrototypeOf()可以识别基于组合继承创建的对象

例如

 function SuperType(name) {
            this.name = name;
            this.colors=["red","blue","yellow"];
        }
       SuperType.prototype.sayName = function () {
           console.log(this.name);
       };
        function SubType(name,age) {
            SuperType.call(this,name);
            this.age = age;
        }
        SubType.prototype = new SuperType();
        SubType.prototype.constructor = SubType;
        SubType.prototype.sayAge = function () {
            console.log(this.age);
        };
        var instance1 = new SubType("Mike",21);
        instance1.colors.push("black");
        console.log(instance1.colors);
        instance1.sayName();
        instance1.sayAge();

        var instance2= new SubType("Greg",29);
        console.log(instance2.colors);
        instance2.sayName();
        instance2.sayAge();

结果
这里写图片描述

分析
(1)SubType构造函数在调用SuperType构造函数时传入name参数,又定义了自己的属性age

(2)SuperType的实例赋值给了SubType的原型,又在新原型上定义了方法sayAge()。

(3)两个不同的SubType实例分别有自己的属性,又可以使用相同的方法

问题

会调用两次超类型构造函数,一次是在创建子类型原型的时候,另一次是在子类型构造函数内部

例如

 SuperType.call(this,name);//第二次调用SuperType()
 ...
 SubType.prototype = new SuperType();//第一次调用SuperType()

原型式继承

原理

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

例如

 function object(o) {
        function F() {}
        F.prototype = o;
        return new F();
    }

从本质上看,object()对传入其中的对象执行了一次浅复制

例如

  function object(o) {
        function F() {}
        F.prototype = o;
        return new F();
    }

    var person = {
        name:"Mike",
        friends:["john","xiao","ha"]
    };
    var aPerson = object(person);
    aPerson.name = "Greg";
    aPerson.friends.push("Bob");

    var yPerson = object(person);
    yPerson.name = "Linda";
    yPerson.friends.push("Barbie");

    console.log(person.friends);

结果
这里写图片描述

规范化原型继承

ECMAScript5通过Object.create()方法规范了原型式继承。这个方法接收两个参数:一个用作新对象原型的对象和(可选)一个为新对象定义额外属性的对象。

例如:传入一个参数

 var person = {
        name:"Mike",
        friends:["john","xiao","ha"]
    };
    var aPerson = Object.create(person);
    aPerson.name = "Greg";
    aPerson.friends.push("Bob");

    var yPerson =  Object.create(person);
    yPerson.name = "Linda";
    yPerson.friends.push("Barbie");

    console.log(person.friends);

结果
这里写图片描述

例如:传入第二个参数,即属性的描述符

  var person = {
        name:"Mike",
        friends:["john","xiao","ha"]
    };
    var aPerson = Object.create(person,{
        name:{
            value:"Greg"
        }
    });
    console.log(aPerson.name);

结果
这里写图片描述

优点

如果只想让一个对象与另一个对象保持类似的情况,可以用原型式继承

问题

引用类型值的属性始终共享

寄生式继承

原理

创建一个仅用于封装继承过程的函数,在内部以某种方式增强对象,最后再返回对象

例如

 function createAnother(original) {
        var clone = Object.create(original);
        clone.sayHi = function () {
            console.log("Hi");
        };
        return clone;
    }

    var person = {
        name:"Mike",
        friends:["Shelby","Court","Van"]
    };
    var aPerson = createAnother(person);
    aPerson.sayHi();

结果、
这里写图片描述

问题

不能做到函数复用而降低效率

寄生组合式继承

原理

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

例如

function inheritPrototype(subType,superType) {
      var prototype = Object.create(superType.prototype);
      prototype.constructor = subType;
      subType.prototype = prototype;
  }

优点

不必为了指定子类型的原型而调用超类型的构造函数

例如

 function inheritPrototype(subType,superType) {
      var prototype = Object.create(superType.prototype);
      prototype.constructor = subType;
      subType.prototype = prototype;
  }
  function SuperType(name) {
      this.name = name;
      this.colors=["red","blue","black"];

  }
  SuperType.prototype.sayName = function () {
      console.log(this.name);
  };
  function SubType(name,age) {
      SuperType.call(this,name);
      this.age = age;

  }
  inheritPrototype(SubType,SuperType);
  SubType.prototype.sayAge = function () {
      console.log(this.age);
  }

分析:

(1)高效率体现在它只调用了一次SuperType构造函数,避免在SubType.prototype上面创建不必要的、多余的属性。

(2)原型链保持不变

(3)正常使用instanceof和isPrototypeOf()

总结

(1)原型式继承:可以不必预定义构造函数的情况下实现继承,其本质是执行对给定对象的浅复制

(2)寄生式继承:基于某个对象或者某些信息创建一个对象,然后增强对象,最后返回对象

(3)寄生组合式继承:集寄生式继承和组合继承的优点于一身,是引用类型最理想的继承方式

参考

《JavaScript高级程序设计(第3版)》

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值