javascript继承方式

99 阅读2分钟

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')