Javascript面向对象编程-继承

前言

继承是面向对象编程特性之一。Javascript是基于原型以及原型链来实现的。在Javascript面向对象编程-简介中讲到了继承,只是介绍了其中一个继承的方式。此文将介绍其他的继承方式。


一、原型链继承

 至于什么是原型链我就不过多讲解。会在Javascript基础中讲到。可以自行运行例子看看对象内部结构自行体会。

// 形状
function Shape(edges) {
  this.edges = edges;
}

Shape.prototype.girth = function () {
  throw new Error("子类实现该方法...");
};

function Square(length) {
  this.length = length;
}

// 改写正方形的原型 将父类实例赋予正方形的原型
Square.prototype = new Shape(4);

// 重写父类原型方法 
Square.prototype.girth = function () {
  return this.length * this.edges;
};

const s = new Square(10);

console.log(s.girth()); // 40  边长 * 边数

缺点:

1. 原型属性被实例共享

2. 子类型实例化不能传参给父类型 

二、 盗用继承

function Person(name, age) {
  this.name = name;
  this.age = age;
}

function Student(name, age, studentId) {
  Person.call(this, name, age);
  this.studentId = studentId;
}

解决了子类型实例化时不能传递参数给父类型。但是不能继承父类型的原型方法。基本此类继承不能单独使用。 

三、组合继承

function Vehicles(wheelNumber) {
  this.wheelNumber = wheelNumber;
}

Vehicles.prototype.run = function () {
  console.log("running......");
};

function Bicycle(wheelNumber) {
  Vehicles.call(wheelNumber);
}

Bicycle.prototype = new Vehicles();

const b = new Bicycle();

b.run();

通过盗用继承继承父类型属性,原型链继承父类型原型方法。 但是子类型实例化是要调用两次父类型构造函数。一次子类的构造函数,一次将父类型实例给到子类型原型中。有点效率问题。

四、原型式继承

let person = {
  name: "",
  age: 18,
};

let lucy = Object.create(person, {
  name: {
    value: "Lucy",
  },
  age: {
    value: 30,
  },
});

console.log(lucy); // 此时lucy的原型就是 person 与原型链继承类似

五、 寄生式继承

function inherit(original, options) {
  let clone = Object.create(original, options);
  clone.sayName = function () {
    console.log(`My name is ${this.name}`);
  };
  return clone;
}
let person = {
  name: "",
  age: 18,
};

let lucy = inherit(person, {
  name: {
    value: "Lucy",
  },
  age: {
    value: 30,
  },
});

console.log(lucy.sayName()); // My name is Lucy

在inherit函数中对子类型进行增强。但是这样导致难以复用 

六、寄生式组合继承

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

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.sayName = function () {
  console.log(`My name is ${this.name}`);
};

function Student(name, age, studentId) {
  Person.call(name, age);
  this.studentId = studentId;
}
inheritPrototype(Person, Student);

Student.prototype.getStudentId = function () {
  return this.studentId;
};

此继承就解决了组合继承的效率问题。寄生组合继承算是最佳的继承。仅限ES6之前。 

七、ES6 Class继承

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  sayName() {
    console.log(`My name is ${this.name}`);
  }
}

class Student extends Person {
  constructor(name, age, studentId) {
    super(name, age);
    this.studentId = studentId;
  }
  getStudentId() {
    return this.studentId;
  }
}

const s = new Student("Lucy", "12", "S0000L201612001923");

s.sayName(); // My name is Lucy

console.log(s.getStudentId()); // S0000L201612001923

ES6使开发者以类的方式编写Javascript代码。但是底层还是基于原型方式继承。在浏览器打印后观察不难发现 。


总结

此文主要介绍了JavaScript的继承方式。其中的原理可以自行打印看看其中的变化,慢慢体会。如果还是不甚理解,后续会讲解原型、构造函数、实例之间的关系。望见谅!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值