JS - 继承

64 阅读3分钟

先来认识一下继承

当前有两个构造函数的情况下,他们两个是没有任何联系的,现在想让 Stu 构造函数也能使用 Person 构造函数的属性和方法,那么就可以说是 Stu 这个构造函数 继承自 Person 这个构造函数, Stu 是 Person 的子级,Person 为 Stu 的父级

1.原型方式继承
这个方式是用自定义原型的方式来完成继承,有两个缺点:

1. 原本原型上的方法不能再使用了,因为原型对象已经被修改了
2. 继承到的属性并不在自己身上,而是在原型对象身上

// 构造函数1.
function Person(name) {
this.name = name
}
Person.prototype.init = function() {
    console.log('我是 Person 原型上的方法')
}

// 构造函数2.
function Stu(age) {
    this.age = age
}
Stu.prototype.SayHi = function() {
    console.log('你好')
}

Stu.prototype = new Person('张三')

const S1 = new Stu(18)
console.log('Stu的实例化对象',S1)  
console.log(S1.name) // 张三
console.log(S1.age)  // 18
S1.SayHi() // 这个方法不能再使用,会报错
2. 构造函数方式继承
核心是把父类构造函数当作普通函数调用,并利用 call 来修改这个函数内部的 this 指向(如果不修改的话,函数的 this 指向了其他的对象),也有两个缺点

1. 只能调用父类的属性,方法继承不到
2. 每次调用子级函数的时候,子级函数内部还会调用一次父级函数

// 构造函数1.
function Person(name) {
    this.name = name
}
Person.prototype.init = function() {
    console.log('我是 Person 原型上的一个方法')
}

// 构造函数2.
function Stu(age,name) {
    this.age = age
    // 将 Person 内部的 this 指向 修改为 Stu 构造函数内部创建出来的对象,并传了一个形参 name 给 Person
    Person.call(this,name)
}
Stu.prototype.SayHi = function() {
    console.log('你好')
}

const S1 = new Stu(18,'张三')
console.log(S1.name)  // 张三
S1.init()  // 没有继承到,无法使用,会报错

3. 组合继承

核心就是把原型和构造函数两种方式整合到了一起,缺点就是属性会有两个

// 构造函数1.
function Person(name) {
    this.name = name
}
Person.prototype.init = function() {
    consloe.log('我是 Person 原型上的方法')
}

// 构造函数2.
function Stu(age,name) {
    this.age = age
    
    Person.call(this,name)
}
Stu.prototype.SayHi = function() {
    console.log('你好')
}

Stu.protrtype = new Person('这个字符串没有意义')
const S1 = new Stu(18,'张三')
// 这里的输出结果会是张三,因为访问S1的name属性,会先在对象自身查找,找到了就直接使用,停止查找
console.log(S1.name)  
4. 拷贝继承
// 构造函数1.
function Person(name) {
    this.name = name
}
Person.prototype.init = function() {
    console.log(''我是 Person 原型上的一个方法)
}


// 构造函数2.
function Stu(age) {
    this.age = age
    
    const p1 = new Person('张三')
    for(let key in p1) {
        // key 是属性 p1[key]是对应的属性值
        Stu.prototype[key] = p1[key]
    }
}
Stu.prototype.sayHi = function() {
    console.log('你好')
}

const s1 = new Stu(18)
console.log(s1)
5. ES6类的继承
语法要求:

1: 书写子类的时候,class 子类名 extends 父类类名{...}
2: 书写 constructor 的时候,内部需要书写 super('父类需要的参数')

注意:

1: extends 和 super 同时出现才能完成继承
2: super 必须出现在 constructor 的第一行

另外,ES6 类继承 也能继承 ES5 的构造函数,只要把父类函数换成普通构造函数即可
// 父类.
class Person{
    constructor(name) {
        this.name = name
    }
    init() {
        console.log('我是 Person 原型上的一个方法')
    }
}

// 子类.
class Stu extends Person{
    constructor(age) {
        super('父级参数')
        this.age = age
    }
    sayHi() {
        console.log('你好')
    }
}
const s1 = new Stu(18) 
console.log(s1)