JS的几种继承

每天做个总结吧,坚持就是胜利!

    /**
        @date 2021-07-10
        @description JS的几种继承
    */
复制代码

壹(序)

JavaScript中的类并不像其他面向类语言中的类,JS中的类只是一种关联关系,都是通过原型机制去实现,今天总结几种继承方式

贰(继承)

  1. 原型链继承:将子的prototype属性改写为父类的实例对象,这样子类就能使用父类中的属性及方法,同时自己也能重写属性
function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.getInfo = function () {
  console.log(`i'm ${this.name}, ${this.age} years old`);
};

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

Student.prototype = new Person();

const student1 = new Student('E1e', 18, 'student');
const student2 = new Student('wy', 24, 'student');

student1.__proto__.getInfo = function () {
  console.log(
    `i'm ${this.name}, ${this.age} years old, i'm a ${this.profession}, hhh`
  );
};

student1.getInfo(); // 'i'm E1e, 18 years old, i'm a student, hhh'
student2.getInfo(); 'i'm wy, 24 years old, i'm a student, hhh'
复制代码

但是,重写子类原型上的方法时,会导致所有子类实例方法都被覆盖,并且比如上面的student1,自己有name,age属性,__proto__上也有

  1. 构造函数继承:借用构造函数实现继承,核心代码就是在子类执行父类构造函数,并改变this指向
function Person(name, age) {
  this.name = name;
  this.age = age;
  this.getInfo = function () {
    console.log(`i'm ${this.name}, ${this.age} years old`);
  };
}
function Student(name, age) {
  Person.call(this, name, age);
}

const student = new Student('E1e', 18);
student.getInfo(); // 'i'm E1e, 18 years old'
复制代码

这种继承方式很简单,就是在子类改变this并调用父类函数,这样子类就拥有父类上的属性及方法了,但是无法继承父类原型上的属性及方法,而且每个子类实例都要去调用父类函数,性能消耗严重

  1. 组合继承:将原型链继承与构造函数继承组合实现继承,用原型链实现父类原型上的继承,用构造函数实现父类自身的继承
function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.getInfo = function () {
  console.log(`i'm ${this.name}, ${this.age} years old`);
};

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

Student.prototype = new Person();

const student = new Student('E1e', 18, 'student');

student.getInfo();
复制代码

这样虽然继承了父类本身及原型上的属性及方法,但是也有之前两种继承方式的缺点

  1. 原型式继承:使用Object.create方法,将被继承对象指定为子对象的原型
const person = {
    name: 'E1e',
    age: 18
}

const anotherPerson = Object.create(person);
anotherPerson.name = 'wy';
anotherPerson.age = 24;
复制代码

通过Object.create方法指定原型,实现原型式的继承,但是这样就无法传递参数,也容易因为修改原型上的属性方法等,而影响所有实例对象

  1. 寄生组合继承:与组合继承类似,只是在设置子类prototype属性时,使用Object.create方法处理

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

Person.prototype.getInfo = function () {
  console.log(`i'm ${this.name}, ${this.age} years old`);
};

function Student() {
  Person.call(this, ...arguments);
}

Student.prototype = Object.create(Person.prototype);

Student.prototype.constructor = Student;

const student = new Student('E1e', 18);

student.getInfo(); // 'i'm E1e, 18 years old'
复制代码

这就是基于ES5最终实现的一种继承方式了,可以把之前的每一种方式写出来点开每一个子类及实例对象观察,会发现这种方式是看起来最好的

最终继承.jpg

  1. 使用ES6的class,其实也是基于ES5的继承实现的,可以看作是一种语法糖,这里不做介绍,总结一下class与ES5继承的不同点
a. class声明的类与let/const声明的变量一样存在TDZ(暂时性死区)
b. class内部使用严格模式
c. class中的所有内部方法都是不可枚举的(包括静态方法与实例方法)
d. 使用class必须使用new
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享