JS中的继承主要是根据原型链来实现,我们今天就来一步步剖析每一种继承方式的优缺点
方式一:原型链继承
- 套路
- 定义父类型构造函数
- 给父类型的原型添加方法
- 定义子类型的构造函数
- 创建父类型的对象赋值给子类型的原型
- 将子类型原型的构造属性设置为子类型
- 给子类型原型添加方法
- 创建子类型的对象: 可以调用父类型的方法
- 关键
- 子类型的原型为父类型的一个实例对象
sub.showSupperProp()
function Person() {
this.name = null;
this.age = 0;
this.say = function () {
console.log(this.name, this.age);
}
}
let per = new Person();
per.name = "dxy";
per.age = 34;
per.say();
// 在企业开发中如果构造函数和构造函数之间的关系是is a关系, 那么就可以使用继承来优化代码, 来减少代码的冗余度
// 学生 is a 人 , 学生是一个人
function Student() {
// this.name = null;
// this.age = 0;
// this.say = function () {
// console.log(this.name, this.age);
// }
this.score = 0;
this.study = function () {
console.log("day day up");
}
}
// 子类的原型为父类的实例
Student.prototype = new Person();
// 修正Sub.prototype.constructor为Sub本身
Student.prototype.constructor = Student;
let stu = new Student();
stu.name = "zs";
stu.age = 18;
stu.score = 99;
stu.say();
stu.study();
弊端: 当创建的类需要传参时,会出现问题,无法实现属性继承。
企业开发中不常用。
图解:
方式二:借用构造函数继承(假的)
- 套路:
- 定义父类型构造函数
- 定义子类型构造函数
- 在子类型构造函数中调用父类型构造
- 关键:
- 在子类型构造函数中通用super()调用父类型构造函数
function Person(myName, myAge) {
// let per = new Object();
// let this = per;
// this = stu;
this.name = myName; // stu.name = myName;
this.age = myAge; // stu.age = myAge;
this.say = function () { // stu.say = function () {}
console.log(this.name, this.age);
}
// return this;
}
function Student(myName, myAge, myScore) {
// let stu = new Object();
// let this = stu;
Person.call(this, myName, myAge); // Person.call(stu);
this.score = myScore;
this.study = function () {
console.log("day day up");
}
// return this;
}
let stu = new Student("ww", 19, 99);
console.log(stu.score);
stu.say();
stu.study();
弊端:不能动态继承父类原型上的方法
图解:
方式三:组合继承(原型+构造函数继承)
- 利用原型链实现对父类型对象的方法继承
- 利用super()借用父类型构建函数初始化相同属性
function Person(myName, myAge) {
// let per = new Object();
// let this = per;
// this = stu;
this.name = myName; // stu.name = myName;
this.age = myAge; // stu.age = myAge;
// this.say = function () { // stu.say = function () {}
// console.log(this.name, this.age);
// }
// return this;
}
Person.prototype.say = function () {
console.log(this.name, this.age);
}
function Student(myName, myAge, myScore) {
Person.call(this, myName, myAge);
this.score = myScore;
this.study = function () {
console.log("day day up");
}
}
// 注意点: 要想使用Person原型对象中的属性和方法, 那么就必须将Student的原型对象改为Person的原型对象才可以
Student.prototype = Person.prototype;
Student.prototype.constructor = Student;
let stu = new Student("ww", 19, 99);
console.log(stu.score);
stu.say();
stu.study();
注意点: 要想使用Person原型对象中的属性和方法, 那么就必须将Student的原型对象改为Person的原型对象才可以
弊端:
- 由于修改了Person原型对象的constructor属性, 所以破坏了Person的三角恋关系
- 由于Person和Student的原型对象是同一个, 所以给Student的元素添加方法, Person也会新增方法
图解:
方式四:组合继承的终极方案(原型+构造函数继承)
js中继承的终极方法
1.1 在子类的构造函数中通过call借助父类的构造函数
1.2 将子类的原型对象修改为父类的实例对象
function Person(myName, myAge) {
// let per = new Object();
// let this = per;
// this = stu;
this.name = myName; // stu.name = myName;
this.age = myAge; // stu.age = myAge;
// return this;
}
Person.prototype.say = function () {
console.log(this.name, this.age);
}
function Student(myName, myAge, myScore) {
Person.call(this, myName, myAge);
this.score = myScore;
this.study = function () {
console.log("day day up");
}
}
/*
弊端:
1.由于修改了Person原型对象的constructor属性, 所以破坏了Person的三角恋关系
2.由于Person和Student的原型对象是同一个, 所以给Student的元素添加方法, Person也会新增方法
*/
// Student.prototype = Person.prototype;
Student.prototype = new Person();
Student.prototype.constructor = Student;
Student.prototype.run = function(){
console.log("run");
}
let per = new Person();
per.run();
/*
1.js中继承的终极方法
1.1在子类的构造函数中通过call借助父类的构造函数
1.2将子类的原型对象修改为父类的实例对象
*/
图解:
方式五 ES6继承
ES6之前的继承
- 在子类中通过call/apply方法借助父类的构造函数
- 将子类的原型对象设置为父类的实例对象
ES6继承 - 在子类后面添加extends并指定父类的名称
- 在子类的constructor构造函数中通过super方法借助父类的构造函数
class Person{
constructor(myName, myAge){
// this = stu;
this.name = myName; // stu.name = myName;
this.age = myAge; // stu.age = myAge;
}
say(){
console.log(this.name, this.age);
}
}
class Student extends Person{
constructor(myName, myAge, myScore){
// 1.在子类中通过call/apply方法借助父类的构造函数
// Person.call(this, myName, myAge);
super(myName, myAge);
this.score = myScore;
}
study(){
console.log("day day up");
}
}
let stu = new Student("zs", 18, 98);
stu.say();
好喽,此刻需要大家记住终极继承方案哦