继承

140 阅读3分钟

认识继承

实例:
    //构造函数1
    function Person(name) {
        this.name = name
    }
    Person.prototype.init = function () {
        console.log('我是 Persion 原型上的方法')
    }
    //构造函数2
    function Stu (age) {
        this.age = age
    }
    Stu.prototype.sayHi = function(){
        console.log('你好')
    }
    const s1 = new Stu(18)
    console.log(s1)
在上述实例中,如果 s1 对象内部 具有一个属性为 name, 并且 s1 还可以使用 init 方法, name 我们就可以说 Stu 这个构造函数 继承自 Person 构造函数
Stu 是 Person 的子类       Person 是 Stu 的父类

原型继承

原型继承: 利用 自定义原型 的方法实现继承关系
核心: 将子类的原型修改为父类的实例化对象
优点: 可以使用父类的属性和方法, 实现了继承
缺点:
    1. 原本原型上的方法不能再使用了 (因为原型对象被改变成了父类的实例化对象)
    2.继承到的属性并不在自己身上, 而是在 原型对象上(不过不影响使用)
实例:
    //构造函数1
    function Person(name) {
        this.name = name
    }
    Person.prototype.init = function () {
        console.log('我是 Persion 原型上的方法')
    }
    //构造函数2
    function Stu (age) {
        this.age = age
    }
    Stu.prorotype = new Person('彭于晏') //实现继承的主要语句
    Stu.prototype.sayHi = function(){
        console.log('你好')
    }
    const s1 = new Stu(18)
    console.log(s1)

借用构造函数继承

核心: 把父类构造函数当做普通函数调用, 并利用 call 修改这个函数内部的 this 指向(如果不修改的话, 函数的 this 指向了其他的对象)
优点: 把父类的属性全都继承在了自己的身上
缺点: 1. 只能继承父类的属性, 不能继承父类的方法
      2. 每次调用 Stu 的时候, Stu内部还会自动调用一次 Person 函数
例: 
        function Fn (name){
            this.name = name
        }
        Fn.prototype.init = function (){
            console.log('我是添加在 Fn 原型上的方法')
        }
        function Fn2 (age, name){
            this.age = age,
            Fn.call(this, name)
        }
        Fn2.prototype.sayHi = function(){
            console.log('你好')
        }
        const f1 = new Fn2(41,'彭于晏')
        console.log(f1)

组合继承

核心: 把原型继承与借用构造函数继承结合起来使用
优点: 实例化对象上具有继承到的属性, 并且能够继承到父类原型上的方法
缺点: 实例化对象上与原型对象上, 都有父类的属性(多了一套属性,但是不影响使用)
例:
    function Fn (name){
        this.name = name
    }
    Fn.prototype.init = function(){
        console.log('我是添加在 Fn 原型上的方法')
    }
    fucntion Fn2 (age, name) {
        this.age = age
        Fn.call(this,name)
    }
    Fn2.prototype = new Fn()
    Fn2.prototype.sayHi = fucntion (){
        console.log('我是添加在 Fn2 原型上的方法')
    }
    const f1 = new Fn2(23,'秦霄贤')
    console.log('Fn2的实例化对象:', f1)
    f1.init()

拷贝继承

通过for...in遍历对象,以及可以遍历对象 的构造函数的 原型上的 方法来实现拷贝继承
例:
    fonction Fn1 (age) {
        this.age = age
    }
    Fn1.prototype.init = ()=>{
        console.log('我是添加在 Fn1 原型上的方法')
    }
    function Fn2 (name,age){
        this.name = name
        const f1 = new Fn1('秦霄贤')
        for(let key in f1){
            Fn2.prototype[key] = f1[key]
        }
    }
    Fn2.prototype.sayHi = () =>{
        console.log('你好')
    }
    const f2 = new Fn2('秦霄贤',24)
    consol.log('Fn2的实例化对象:', f2)

ES6 类 的继承

语法要求:
        1.书写 子类 的语法: class 子类类名 extends 父类类名{...}
        2.书写 constructor 的时候: 内容需要写 super('父类需要的参数')
注意:
     1.extendssuper 必须同时出现才能完成继承
     2.super 必须出现在 constructor 的第一行
扩展:
    ES6 类也能继承 ES5 的构造函数
        验证方法:将 父类 更改为 ES5 的构造函数写法即可
例:
    //父类
    class Fn {
        constructor (name){
            this.name = name
        }
        inir(){
            console.log('我是添加在 Fn 原型上的方法')
        }
    }
    //验证:用ES5书写父类
    function Fn(name){
        this.name = name
    }
    Fn.prototype.init = () => {
        console.log('我是添加在 Fn 原型上的方法')
    }
    //子类
    class Fn2 extends Fn{
        constructor(age, name){
            super(name)
            this.age = age
        }
        sayHi(){
            console.log('我是添加在 Fn2 原型上的函数')
        }
    }
    const f1 = new Fn2(24,'秦霄贤')
    console.log(f1)
    console.log(f1.name)