js 继承 实现方式

时间:2021-2-20 作者:admin
  1. 原型链继承

(将超类(父类)的实例对象 赋值给 子类的原型对象)

  • 优点: 简单易于实现
  • 缺点
    • 不可多继承
    • 子类不能向超类传递参数
    • 子类实例成员之间共享父类的属性,如果该属性是引用数据类型,子类实例成员之间将相互影响。
    • 子类若要声明自己的原型方法需在继承之后
  function SuperClass() {
    this.name = "super";
    this.list = []; //被共享,其中一个子类成员push,其他子类实例成员拿到的list 也会随之变化
  }
  SuperClass.prototype.say = function () {
    console.log("wo shi super");
  };
  SuperClass.prototype.push = function (p) {
    this.list.push(p);
  };

  function SubClass() {
    this.name = "sub";
  }
  SubClass.prototype.say = function () {
    console.log("wo shi sub");
  };

  SubClass.prototype = new SuperClass(); //继承父类的实例对象

  SubClass.prototype.print = function () {
    console.log("print sub");
  };

  const instance1 = new SubClass();
  instance1.say(); // wo shi super
  instance1.push("instance1"); //将影响其他的子类实例成员的list属性
  instance1.print();

  const instance2 = new SubClass();
  console.log(instance2.list); //  ["instance1"]; 
  1. 借用构造函数继承

(调用父类的构造函数)

  • 优点
    • 可以多继承
    • 子类可以向超类传递参数
    • 继承引用类型的属性子类实例成员之间没有影响
  • 缺点
    • 不能继承原型链上的属性和方法
    • 方法定义在构造函数内,不能被复用(每个子类去继承都是新的函数)
function SuperClass(age) {
  this.name = "super";
  this.age = age;
 // 不能被复用
  this.say = function () {
    console.log("wo shi super");
  };
}
//不能被继承
SuperClass.prototype.print = function () {
  console.log("wo shi super");
};

function SubClass() {
  SuperClass.call(this, 123);
}

const instance = new SubClass();
console.log(instance.age);
  1. 原型式继承

(本质是对象的浅复制)

  • 优点:简单易于实现
  • 缺点: 同原型链继承一样,超类引用类型被子类共享
 function CloneObj(o) { 
    const Fn = function () {};
    Fn.prototype = o;
    return new Fn();
  }

  const superObj = {
    sex: "男",
    things: ["money", "house"]
  };

  const sub1 = CloneObj(superObj);
  const sub2 = CloneObj(superObj);

  sub1.things.push("car"); //将影响其他子类的things属性
  console.log(sub2.things); // ["money", "house", "car"]
    上面的cloneObj 函数本质上对传入的对象进行了一次浅复制,在传入一个参数的情况下,作用于Object.create()类似.<https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create>
  1. 组合继承

(原型链继承 + 借用超类构造函数)

  • 优点
    • 父类原型方法可以实现复用
    • 超类引用类型属性共享 子类间不会相互影响
  • 缺点
    • 构造函数被调用两次,创建了俩两超类实例
 function SuperClass(age) {
   this.name = "super";
   this.age = age;
 }
 SuperClass.prototype.say = function () {
   console.log("wo shi super");
 };

 function SubClass() {
   SuperClass.call(this, 123);
 }

 SubClass.prototype = new SuperClass();
 SubClass.prototype.constructor = SubClass; //重新添加构造函数指向

 const instance = new SubClass();
  1. 寄生式组合继承

(目前最完美的继承实现方式)

function SuperClass(age) {
  this.name = "super";
  this.age = age;
}
SuperClass.prototype.say = function () {
  console.log("wo shi super");
};

function SubClass() {
  SuperClass.call(this, 123);
}

//继承函数
function inherit(sup, sub) {
  const Fn = function () {};
  Fn.prototype = sup.prototype;
  sub.prototype = new Fn();
  sub.prototype.constructor = sub;

 // sub.prototype = Object.create(sup.prototype)
}

inherit(SuperClass, SubClass);
const instance = new SubClass();
  1. es6继承
class SuperClass {
  constructor(name = "super", age = 123) {
    this.name = name;
    this.age = age;
  }

  say() {
    console.log(`wo shi ${this.name}, age is ${this.age}`);
  }
}

class SubClass extends SuperClass {
  constructor(name, age) {
    super(name, age); //继承超类属性并传递参数
  }
  say() {
    super.say(); //继承超类方法
  }
}
class SubClass2 extends SuperClass {
  constructor(name, age) {
    super(name, age); //继承超类属性并传递参数
  }
  say() {
    super.say(); //继承超类方法
  }
}

const instance1 = new SubClass("sub1", 345);
const instance2 = new SubClass2("sub2", 456);
instance1.say(); // wo shi sub, age is 345
instance2.say(); // wo shi sub2, age is 456

console.log(instance1.say == instance2.say); // false 
声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。