# js 中实现继承的 6 种方式

- 作为一个合格的cv工程师,你可以不会,但我不允许你需要的时候找不到,收集一下继承的6种方式

# 原型链继承

function Person(name, age) {
  (this.name = name), (this.age = age), (this.setName = function () {});
}
Person.prototype.setAge = function () {};
function Student(name, age, price) {
  Person.call(this, name, age);
  this.price = price;
}
var s1 = new Student('Tom', 20, 15000);
console.log(s1);
  • 核心:拿父类实例来充当子类原型对象
  • 缺点:
    • 无法继承构造函数中的属性
    • 创建子类实例时,无法向父类构造函数传参
    • 对象中存在多余的属性

# 借用构造函数继承

function Person(name, age) {
  (this.name = name), (this.age = age);
}
Person.prototype.setAge = function () {
  console.log('111');
};
function Student(price) {
  this.price = price;
  this.setScore = function () {};
}
Student.prototype.sayHello = function () {};
Student.prototype = new Person();
Student.prototype.sayHello = function () {};
var s1 = new Student(15000);
var s2 = new Student(14000);
console.log(s1, s2);
s1.play.push(4);
console.log(s1.setAge, s2.setAge);
console.log(s1.__proto__ === s2.__proto__);
console.log(s1.__proto__.__proto__ === s2.__proto__.__proto__);
console.log(s1.__proto__.__proto__.__proto__ === Object.prototype);
  • 核心:借父类的构造函数来增强子类实例,相当于把父类的实例属性复制一份给子类实例
  • call 方法:父类构造函数.call(子类实例,参数一,参数二,参数三……)
  • apply 方法:父类构造函数.apply(子类实例,[参数一,参数二,参数三……]

# 原型链+借用构造函数的组合继承

function Person(name, age) {
  (this.name = name), (this.age = age), (this.setAge = function () {});
}
Person.prototype.setAge = function () {
  console.log('111');
};
var p1 = new Person('jack', 15);
function Student(name, age, price) {
  Person.call(this, name, age);
  this.price = price;
  this.setScore = function () {};
}
Student.prototype = new Person();
Student.prototype.constructor = Student; //组合继承也是需要修复构造函数指向的
Student.prototype.sayHello = function () {};
var s1 = new Student('Tom', 20, 15000);
var s2 = new Student('Jack', 22, 14000);
console.log(s1.constructor); //Student
console.log(p1.constructor); //Person
  • 原型链继承方法
  • 借用构造函数法继承属性
  • 缺点
    • 原型对象存在多余的属性
    • 多次执行父类构造函数

# 寄生组合继承法(完美版)

function Person(name, age) {
  (this.name = name), (this.age = age), (this.setAge = function () {});
}
Person.prototype.setAge = function () {
  console.log('111');
};
function Student(name, age, price) {
  Person.call(this, name, age);
  this.price = price;
  this.setScore = function () {};
}
Student.prototype = Person.prototype;
Student.prototype.sayHello = function () {};
var s1 = new Student('Tom', 20, 15000);
console.log(s1);
console.log(s1 instanceof Student, s1 instanceof Person); //true true
console.log(s1.constructor); //Person
  • 属性:借用构造函数法 call,apply,bind 继承
  • 方法:原型式继承

# 原型式继承(继承方法)

function Person(name, age) {
  (this.name = name), (this.age = age);
}
Person.prototype.setAge = function () {
  console.log('111');
};

function Student(name, age, price) {
  Person.call(this, name, age);
  this.price = price;
  this.setScore = function () {};
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
var s1 = new Student('Tom', 20, 15000);
console.log(s1 instanceof Student, s1 instanceof Person); // true true
console.log(s1.constructor); //Student
console.log(s1);
  • 核心:先创建一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回了这个临时构造函数的一个新实例

# ES6 class 继承

class Person {
  //调用类的构造方法
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  //定义一般的方法
  showName() {
    console.log('调用父类的方法');
    console.log(this.name, this.age);
  }
}
let p1 = new Person('kobe', 39);
console.log(p1);
//定义一个子类
class Student extends Person {
  constructor(name, age, salary) {
    super(name, age);
    this.salary = salary;
  }
  showName() {
    //在子类自身定义方法
    console.log('调用子类的方法');
    console.log(this.name, this.age, this.salary);
  }
}
let s1 = new Student('wade', 38, 1000000000);
let s2 = new Student('kobe', 40, 3000000000);
console.log(s1.showName === s2.showName); //true
console.log(s1);
s1.showName();
  • 继承了属性和方法
Last Updated: 6/2/2022, 3:50:31 AM