# 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();
- 继承了属性和方法