JavaScript中的继承

一、关于继承我所知道的分类

继承在java中可能更能一目了然一些,class代表类,extends代表继承,es6中将这种模式的继承已经加了进去。所以以后我们也可以用完整且易懂的继承了。这里我按照会不会使用Object.create()方法来划分。
不使用Object.create()的继承。
原型继承 、构造函数继承 、 组合继承
使用Object.create()的继承。
原生式继承 、 寄生式继承 、寄生组合继承 、 es6的class继承

二、继承类型详解

1.原型继承

    原型继承,将父类的实例对象作为子类的原型。
  SubType.prototype = new SupType();  
   //修正子类构造函数的指向,不修改则指向SupType   
  SubType.prototype.constructor = SubType

优点:父类方法可以复用
缺点:(1) 父类的引用属性会被所有子类实例共享. (2) 子类构建实例时不能向父类传递参数
2.构造函数继承
构造函数继承则是使用call函数,引用执行父类函数,将父类构造函数的内容复制给了子类的构造函数。

 function SupType() {
    this.name = "zhangsan";
  }
  function SubType(name, age) {
    SubType.call(this, name);
    this.age = age;
  }

优点:父类的引用属性不会被共享,子类构建实例时可以向父类传递参数
缺点:父类的方法不能复用,子类实例的方法每次都是单独创建的。
3.组合继承
组合继承是将原型继承和构造函数继承的优点糅合在一起,组成了组合继承,核心代码如下。

 function SupType() {
    this.name = "zhangsan";
  }
  function SubType(name, age) {
    SupType.call(this, name);
    this.age = age;
  }

SubType.prototype = new SupType();
优点:父类的引用属性不会被共享,子类构建实例时可以向父类传递参数,父类的方法可以被复用
缺点:两次调用父类构造函数。第一次 SupType.call(this, name)第二次new SupType() 造成性能上的浪费。
4.原型式继承
原型式继承的主要原理是创建一个临时的函数,将函数的prototype修改为父类的复制对象,具体代码如下:

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

  var person = {
    name: "zhangsan",
    friends: ["lisi", "wangwu"]
  };

  var anotherPerson = object(person);
  anotherPerson.name = "zhangsan1";
  anotherPerson.friends.push("Bob");

  var yetAnotherPerson = object(person);
  yetAnotherPerson.name = "zhangsan2";
  yetAnotherPerson.friends.push("Mary");
  console.log(person.friends); //"lisi", "wangwu", "Bob", "Mary
  console.log(anotherPerson.friends); //"lisi", "wangwu", "Bob", "Mary
  console.log(yetAnotherPerson.friends); //"lisi", "wangwu", "Bob", "Mary
(ps:这里说明下Object.create(obj) 其实和Object(obj)是完全相同的,对一个对象进行复制)

优点:父类方法可以复用
缺点:(1)父类的引用属性会被所有子类实例共享 。(2)子类构建实例时不能向父类传递参数
4.寄生继承
使用原型式继承获得一个目标对象的浅复制,然后增强这个浅复制的能力。即给浅复制出来的对象增加自定义方法。

function createAnother(original){ 
  var clone=object(original);    //通过调用函数创建一个新对象
  clone.sayHi = function(){      //以某种方式来增强这个对象
      alert("hi");
  };
  return clone;                  //返回这个对象
}

5.寄生组合继承
寄生组合继承顾名思义,将原型式继承和组合继承结合起来。省去了创建两次对象的性能问题还解决了父类复用及可传参的问题,寄生组合继承可以说是比较完美的了。

function inheritPrototype(subType, superType){
    var prototype = object(superType.prototype); // 创建了父类原型的浅复制
    prototype.constructor = subType;             // 修正原型的构造函数
    subType.prototype = prototype;               // 将子类的原型替换为这个原型
}

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

SuperType.prototype.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);
}

6.class继承

class A {}
class B extends A {
  constructor() {
    super();
  }
}
原理如下:
class A {
}
class B {
}
Object.setPrototypeOf = function (obj, proto) {
  obj.__proto__ = proto;
  return obj;
}
// B 的实例继承 A 的实例
Object.setPrototypeOf(B.prototype, A.prototype);
// B 继承 A 的静态属性
Object.setPrototypeOf(B, A);

ES6的class相当于是ES5继承的语法糖的,ES6继承中子类的构造函数的原型链指向父类的构造函数了。ES5中其实是复制构造函数,没有原型链的指向。

三、总结

JS的继承除了构造函数继承之外都基于原型链构建的
可以用寄生组合继承实现ES6中class extends式的继承,但是不是完全等于的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值