JavaScript如何实现继承的7种方式总结

什么是继承 用官方点的话讲继承是面向对象三大特征之一,可以使得子类具有父类的属性和方法,同时还可以在子类中重新定义以及追加属性和方法。通俗的来说继承就是子类可以

什么是继承

用官方点的话讲继承是面向对象三大特征之一,可以使得子类具有父类的属性和方法,同时还可以在子类中重新定义以及追加属性和方法。通俗的来说继承就是子类可以从父类那里复用一些属性和方法,从而达到复用代码的一个效果。

实现继承的6种方式

  • 原型链继承
  • 构造函数继承
  • 组合继承(伪经典继承)
  • 原型式继承
  • 寄生式继承
  • 寄生组合式继承
  • class 类继承

1. 原型链继承

function Person() {
    this.name = 'bruce'
    this.age = 18
    this.gender = '男'
    this.like = {
        sport: 'running',
        book: 'JavaScript'
    }
    this.getName = function() {
        console.log(this.name);
    }
}

function Student() {
    this.school = '新华小学'
}

let s = new Student()
console.log(s.name);   // 未继承前 undefined

Student.prototype = new Person()  // 继承之后
let s1 = new Student()
s1.getName()  // bruce
console.log(s1.like.book);  // JavaScript
s1.like.book = 'Java'   // 修改引用类型的值
s1.name = 'jack'  // 修改非引用类型的值
console.log(s1.like.book);  // Java
s1.getName()  // jack
console.log('----------');
let s2 = new Student()
s2.getName()  // bruce
console.log(s2.like.book);  // Java

所谓的原型链继承,在我的理解就是子类通过原型链来继承到父类的属性,在上面的代码中我们也可以看到在子类实例s没有继承到父类的属性时,子类去访问父类才有的属性值为:undefined

在将父类实例对象挂载到子类Student构造函数的原型上面后,那么此时子类的原型上面就有了父类的全部属性。因为Person的实例对象被显示的挂载到了Student的原型上面。所以子类在继承之后,所有实例化的子类都拥有了跟父类一样的属性,于是这样子类就通过原型链实现了继承。

优点: 子类可以继承到父类的方法。

缺点:

  • 会在子类实例上共享父类所有的引用类型数据,也就是子类的原型被父类属性覆盖。
  • 子类实例不能给父类构造函数传参。
function Person(t) {
    this.property = t
}

function Student(t) {
    this.typeproperty = t
}
Student.prototype = new Person()
let s=new Student('a')
console.log(s.property)  // undefined
console.log(s.typeproperty)  // a

这样子类实例传的参数就不能给到父类构造函数里面了。

2. 构造函数继承

function Person(name,age) {
    this.name = name
    this.age = age
    this.like = {
        sport: 'running',
        book: 'JavaScript'
    }
    this.getName = function () {
        console.log(this.name);
    }
}
Person.prototype.sayHello = function () {
    console.log('你好');
}

function Student(name, age,) {
    Person.call(this, name, age)  // 借用构造函数
}

let s1 = new Student('bruce',18)
s1.getName()   // bruce
s1.name='jack'
s1.getName()  // jack
s1.like.sport='swimming'
console.log(s1.like.sport);  // swimming
console.log('------');
let s2=new Student('lucy',19)
s2.getName()  // lucy
console.log(s2.like.sport);  // running 

构造函数继承就是使用强制改变 this 指向,借用一个构造函数继承。相较于原型链继承,构造函数继承不会共享父类上的引用类型数据,不会互相影响。

缺点:1.不能访问到父类原型属性上面的方法和参数,即 Person.prototype 上的都不能访问到。

Person.prototype.sayHello = function () {  // 在 Person 的原型上面加一个方法
    console.log('你好');
}

let s1 = new Student('bruce',18)
s1.sayHello()  // s1.sayHello is not a function

3. 组合继承(伪经典继承)

相较于原型链继承,构造函数继承好像已经非常完美了,但是它还是存在着一个最大的缺点就是:不能继承到父类的原型上面的属性。但是原型链继承就好像没有这个问题,如果将这两个继承方式组合起来搭配使用