1.原型链继承:子类的原型为父类的一个实例对象
优点:简单易实现;
缺点:
- 无法实现多继承
- 来自原型对象的所有属性被所有实例共享
- 创建子类实例时,无法向父类构造函数传参
- 想要为子类新增属性和方法必须放在原型指向之后
function Person() {
this.name = 'zhangsan'
this.age = 18
this.favorite = ['football']
}
Person.prototype.namePrint = function() {
console.log(this.name)
}
function Student(name, age, sex) {
this.name = name
this.age = age
this.sex = sex
}
Student.prototype = new Person()
Student.prototype.agePrint = function() {
console.log(this.age)
}
let stu = new Student('lisi', 19, 'female')
/*
(1)继承了Person的方法namePrint()
(2)但是属性值name、age不能复用Person中的
(3)favorite属性为所有实例共享
*/
2.借用构造函数继承
(在子类构造函数用call()调用父类构造函数) 优点:
- 解决共享问题
- 创建子类时,可向父类传参
- 可实现多继承(多调用几次call) 缺点:
- 实例并非父类的实例,而是子类的实例
- 只能继承父类的实例属性和方法,不能拿到原型脸上的实例属性和方法
- 无法实现函数复用,每个子类的都有父类实例函数的副本,影响性能
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.agePrint = function() {
console.log(this.age)
}
function Student(name, age, sex) {
Person.call(this, name, age)
this.sex = sex
}
let s1 = new Student('lisi', 18, 'female')
let p1 = new Person('zhangsan', 19)
console.log(s1.__proto__.constructor)
console.log(p1.__proto__.constructor)
/*
(1)s1实例拿不到Person原型链上的agePrint()方法,无法实现函数复用
(2)每个子类实例都有父类函数的副本,影响性能,call()调用
*/
3.原型链+借用构造函数的组合继承
思路就是属性为调用call()方法传参,方法则通过原型继承
优点:
- 可以同时继承
- 不存在引用共享
- 可传参
- 函数可复用 缺点:调用父类构造函数两次,生成两份实例
function Person(name, age) {
this.name = name
this.age = age
this.favorite = ['football']
console.log('调用Person')
}
Person.prototype.namePrint = function() {
console.log(this.age)
}
function Student(name, age, sex) {
Person.call(this, name, age)
this.sex = sex
}
Student.prototype = new Person()
Student.prototype.constructor = Student
Student.sayHello = function() {
console.log('hello')
}
let s1 = new Student('zhangsan', 18, 'female')
let s2 = new Student('lisi', 19, 'female')
4.组合继承优化
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.namePrint = function() {
console.log(this.name)
}
function Student(name, age, sex) {
Person.call(this, name, age)
this.sex = sex
}
Student.prototype = Person.prototype
Student.prototype.constructor = Student
Student.prototype.sayHello = function() {
console.log('hello')
}
let s1 = new Student('zhangsan', 18, 'female')
5.class继承
缺点:存在兼容问题
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
sayHello() {
console.log('hello')
}
}
let p1 = new Person('zhangsan', 19)
class Student extends Person {
constructor(name, age, sex) {
super(name, age)
this.sex = sex
}
agePrint() {
console.log(this.age)
}
}
let stu = new Student('lisi', 18)
6.寄生组合式继承
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.agePrint = function() {
console.log(this.age)
}
function Student(name, age, sex) {
Person.call(this, name, age)
this.sex = sex
}
function create(proto) {
function Fn() {}
Fn.prototype = proto
return new Fn()
}
Student.prototype = create(Person.prototype)
Student.prototype.constructor = Student
let s1 = new Student('zhangsan', 18, 'female')
7.多重继承
关键:assign
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.namePrint = function() {
console.log(this.name)
}
function Parent(favorite) {
this.favorite = favorite
}
Parent.prototype.favoritePrint = function() {
console.log(this.favorite)
}
function Student(name, age, sex, favorite) {
Person.call(this, name, age)
Person.call(this, favorite)
this.sex = sex
}
Student.prototype = Person.prototype
// 混入Parent原型上的favoritePrint()方法
Object.assign(Student.prototype, Parent.prototype)
let stu = new Student('zhangsan', 18, 'female', 'football')