浅识js——继承

51 阅读3分钟

js基础知识——继承

一、继承的方式

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 = new Person ('哈哈')

    Person.prototype.sayHi = function(){
      console.log('你好')
    }

    // console.log('Stu原型对象',Stu.prototype)
    const s1 = new Stu(18)
    // console.log(s1.name) //过程讲解 见老师
    console.log('实例对象',s1)  //继承到的属性并不在自己身上, 而是在 原型对象上

    s1.init()  //原本原型上的方法不能使用了
    s1.sayHi()

2.借用构造函数继承

  • 核心:把父类构造函数当作普通函数调用,并且利用call修改这个函数内部的this指向(如果不修改,函数的this指向了其他的对象)
  • 优点:把父类的属性全部继承在自己身上
  • 缺点:
    1. 只能继承父类的属性,不能继承父类的方法
    2. 每次调用stu时,stu内部还会自动调用一次person函数
    // 构造函数1 (普通函数)
    function Person (name){
      this.name = name
    }

    Person.prototype.init = function(){
      console.log('person上的原型')
    }

    // 构造函数2 
    function Stu (age,name){
      this.age = age
      Person.call(this,name) //改变了函数内部的this指向,相当于stu构造函数内部被自动创建出来的对象
    }
    Person.prototype.sayHi = function(){
      console.log('你好')
    }
    const s1 = new Stu(18,'哈哈')
    s1.init()  //继承不到方法init,

3.组合继承

  • 核心:把原型继承与借用构造函数继承结合起来使用
  • 优点:实例化对象上具有继承到的属性,并且能继承到父类原型上的方法
  • 缺点:实例化对象上,都有父类的属性(多一套属性,但并不影响使用)
    //构造函数1 
    function Person (sex){
      this.sex = sex
    }
    Person.prototype.init = function(){
      console.log('person上的原型')
    }

    // 构造函数2 
    function Stu (age,sex){
      this.age = age
      // 1.借助 构造函数继承,得到父类的属性(放在对象上,并且没有继承父类原型上的方法)
      Person.call(this,sex)
    }
    // 2.利用 原型继承,得到父类的属性(原型上的)与方法
    Stu.prototype = new Person ('man')

    Person.prototype.sayHi = function(){
      console.log('你好')
    }
    // 创建实例化对象
    const s1 = new Stu(18,'women')

    console.log('Stu实例对象',s1)
    console.log('Stu原型对象',Stu.prototype)
    
    // console.log(s1.name)
    s1.sayHi()
    s1.init()

4.拷贝继承

  • 补充: for...in 遍历, 可以遍历到对象的原型上的方法
        // 构造函数1
        function Person(name) {
            this.name = name
        }
        Person.prototype.init = function () {
            console.log('我是 Person 原型上的方法')
        }

        // 构造函数2
        function Stu(age, name) {
            this.age = age

            /**
             *  在 子类构造函数实例化父类构造函数, 得到父类构造函数的实例化对象
             *  然后利用 for...in 可以遍历到原型上的属性这个特点, 将实例化对象的属性与其原型上的方法
             *   一起拷贝到子类构造函数的原型中
            */
            const p1 = new Person('张三')
            for (let key in p1) {
                Stu.prototype[key] = p1[key]
            }
        }
        Stu.prototype.sayHi = function () {
            console.log('你好')
        }

        // 创建实例化对象
        const s1 = new Stu(18, '张三')

        console.log('Stu 实例化对象', s1)
        console.log('Stu 原型对象', s1.__proto__)