javascript的继承实现

继承

ECMAScript 实现继承主要是依靠原型链。包括:
* 原型链
* 借用构造函数
* 组合继承
* 原型式继承
* 寄生式继承
* 寄生组合式继承

采用哪种方式

寄生组合式继承 是引用类型最理想的继承方式。

原型链

通过将一个类型的实例赋值给另一个构造函数的原型实现的。这样,子类型就能够访问超类型的所有属性和方法。

  function SuperType(){
    this.property = true;
  }
  SuperType.prototype.getSuperValue = function(){
    return this.property;
  }

  function SubType(){
    this.subproperty = false;
  }
  // 继承了SuperType
  SubType.prototype = new SuperType();
  SubType.prototype.getSubValue = function(){
    return this.subproperty;
  }

  var instance = new SubType();
  alert(instance.getSuperValue());   // true

原型链继承是通过创建SuperType的实例,并将该实例赋给SubType.prototype实现的。实现的本质是重写SubType的原型对象。

问题:对象实例共享所有继承的属性和方法,包含引用类型的属性。

借用构造函数

解决原型链中包含引用类型值所带来的问题。
在子类型构造函数的内部调用超类型构造函数。这样可以做到每个实例都具有自己的属性,同时还能保证只使用构造函数模式来定义类型。

  function SuperType(name){
    this.name = name;
    this.colors = ["red","blue","green"];
  }

  function SubType(){
    // 继承了SuperType,同时还传递了参数
    SuperType.call(this, "Nicholas");
    // 实例属性
    this.age = 29;
  }

  var instance1 = new SubType();
  instance1.colors.push("black");
  alert(instance1.colors);   // "red,blue,green,black"

  var instance1 = new SubType();
  alert(instance2.colors);   // "red,blue,green"

通过使用call(),我们实际上是在(未来将要)新创建的SubType实例的环境下调用了SuperType构造函数。这样一来,就会在新SubType对象上执行SuperType()中定义的所有对象初始化代码。结果SubType的每个实例就都会具有自己的name和colors属性的副本了。

问题:方法都在构造函数中定义,函数无法复用。超类型的原型中定义的方法,对子类型而言也是不可见的,结果所有类型都只能使用构造函数模式。

组合继承

将原型链和借用构造函数的技术组合到一块。使用原型链继承共享的属性和方法,而通过借用构造函数继承实例属性。

  function SuperType(name){
    this.name = name;
    this.colors = ["red","blue","green"];
  }
  SuperType.prototype.sayName = function(){
    alert(this.name);
  }

  function SubType(name, age){
    // 继承了SuperType的属性
    SuperType.call(this, name);
    // 实例属性
    this.age = 29;
  }
  //继承方法
  SubType.prototype = new SuperType();
  SubType.prototype.sayAge = function(){
    alert(this.age);
  }

  var instance1 = new SubType("Nicholas", 29);
  instance1.colors.push("black");
  alert(instance1.colors);   // "red,blue,green,black"
  instance1.sayName();       // "Nicholas"
  instance1.sayAge();        // 29

  var instance1 = new SubType("Greg", 27);
  alert(instance2.colors);   // "red,blue,green"
  instance2.sayName();       // "Greg"
  instance2.sayAge();        // 27

SuperType构造函数定义了两个属性:name和colors。SuperType的原型定义了sayName()。SubType构造函数在调用SuperType构造函数时传入了name参数,紧接着又定义了它自己的属性age。然后,将SuperType的实例赋值给SubType的原型,然后又在该新原型上定义了方法sayAge()。这样一来,就可以让两个不同的SubType实例既分别拥有自己的属性————包括colors属性,又可以使用相同的方法了。

问题:多次调用超类型构造函数而导致的低效率。

原型式继承

可以在不必预先定义构造函数的情况下实现继承,其本质是执行对给定对象的浅复制。而复制得到的副本还可以得到进一步改造。

  var person = {
    name : "Nicholas",
    friends : ["Shelby","Court", "Van"]
  }

  var anotherPerson = Object.create(person);
  anotherPerson.name = "Greg";
  anotherPerson.friends.push("Rob");

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

  alert(person.friends);   // "Shelby,Court,Van,Rob,Barbie"

问题:和原型链一样,包含引用类型的属性始终都会共享相应的值。

寄生式继承

与原型式继承相似,也是基于某个对象或某些信息创建一个对象,然后增强对象,最后返回对象。

  function createAnother(original){
    var clone = Object.create(original);
    clone.sayHi = function(){
      alert("hi");
    }
    return clone;
  }

createAnother()接收了一个参数,也就是将要作为新对象基础的对象。
然后创建一个original基础对象的副本clone。再为clone对象添加一个新方法sayHi(),最后返回clone对象。

  var person = {
    name : "Nicholas",
    friends : ["Shelby","Court", "Van"]
  }

  var anotherPerson = Object.create(person);
  anotherPerson.sayHi();   // "hi";

以上代码基于person返回了一个新对象————anotherPerson。新对象不仅具有person的所有属性和方法,而且还有自己的sayHi()方法。

问题:与借用构造函数相似,寄生式继承为对象添加函数,会由于不能做到函数复用而降低效率。

寄生组合式继承

集寄生式继承和组合继承的优点于一身,是实现基于类型继承的最有效方式。

  function inheritPrototype(subType, superType){
    subType.prototype = Object.create(superType.prototype);
    subType.prototype.constructor = subType;
  }
  1. 创建超类型原型的一个副本,赋值给子类型的原型;
  2. 为子类型添加constructor属性,从而弥补因重写原型而失去的默认的constructor属性。
  function SuperType(name){
    this.name = name;
    this.colors = ["red","blue","green"];
  }
  SuperType.protot.sayName = function(){
    alert(this.name);
  }

  function SubType(name, age){
    SuperType.call(this, name);
    this.age = age;
  }

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

只调用了一次SuperType构造函数,并且因此避免了在SubType.prototype上面创建不必要的、多余的属性。于此同时,原型链还能保持不变;因此,还能正常使用instanceof和isPrototypeOf()。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值