JavaScript全解析-继承

文章详细介绍了JavaScript中几种继承的方式,包括原型继承、借用构造函数继承、组合继承、ES6的类继承以及拷贝继承、寄生式继承和冒充式继承。每种方式都有其优缺点,例如原型继承能继承属性但属性不在实例本身,而借用构造函数继承则可使属性在实例上但无法继承原型方法。ES6的类继承提供了更规范的语法来实现继承。
摘要由CSDN通过智能技术生成

继承

 

 

●要知道什么是继承
●要知道继承的方式有哪些
●每种的继承方式是如何实现的
什么是继承
●继承关系出现在构造函数和构造函数之间
●当构造函数A 的实例使用了 构造函数B 的属性和方法
●我们就说 构造函数A 继承自 构造函数B
○管 构造函数A 叫做子类
○管 构造函数B 叫做父类
●总结 :继承就是获取存在对象已有属性和方法的一种方式

function Person(name, age) {
      this.name = name
      this.age = age
    }

    Person.prototype.play = function () { console.log('玩游戏') }

    // 将来我创建的 Person 的实例, 就会出现两个属性一个方法
    const p = new Person('Jack', 18)
    console.log(p)

    function Student(classRoom) {
      this.classRoom = classRoom
    }

    // 将来我创建的 Student 的实例
    // 当我的 s 实例能使用 name 属性, age 属性 和 play 方法的时候
    // 我们就说 Student 构造函数继承自 Person 构造函数
    // Student 就是 子类
    // Person 就是 父类
    const s = new Student(2114)
    console.log(s)


复制代码

文章底部扫码,免费领取web前端资料大礼包!

继承的方式有哪些
原型继承
●核心: 让子类的原型指向父类的实例
●优点:
○父类构造函数体内的属性和原型上的方法都可以实现继承
●缺点:
○继承下来的属性不在自己身上, 在自己的原型上
○一个构造函数的实例, 需要在两个地方传递参数
○所有子类的实例, name 和 age 一模一样

<script>
    // 父类
    function Person(name, age) {
        this.name = name
        this.age = age
    }
    Person.prototype.play = function() {
        console.log('玩游戏')
    }
    // 子类
    function Student(classRoom) {
        this.classRoom = classRoom
    }
    // 实现继承
    const p = new Person('Jack', 18)
    Student.prototype = p
    //  此时 s 的 __proto__ 指向谁 ?
    //  指向所属构造函数的 prototype
    //  因为 Student.prototype 就是 就是 Person 的实例
    //  s 的 __proto__ 就是 Person 的实例
    const s = new Student(2114)
    console.log(s)
    // 当你访问 s 的 classRoom 成员的时候
    // 自己有直接使用
    console.log(s.classRoom)
    // 当你访问 s 的 name 成员的时候
    // 自己没有, 去到自己的 __proto__ 上查找
    // 因为自己的__proto__ 就是 Person 的实例
    // 其实就是去到 Person 的实例上查找
    console.log(s.name)
    // 当你访问 s 的 play 成员的时候
    // 自己没有, 去到自己的 __proto__ 上查找
    // 也就是去到 Person 的实例上查找, 发现还是没有
    // 就再去 __proto__ 上查找
    // 自己的 __proto__ 的 __proto__
    // Person 实例      的 __proto__
    // Person 实例 的 __proto__ 就是 Person.prototype
    s.play()
    const s2 = new Student(2115)
    console.log(s2)
</script>


复制代码

借用构造函数继承
●核心: 把父类构造函数当做普通函数调用, 并且改变其 this 指向
●优点:
○子类的所有继承下来的属性都在自己身上
○子类的所有参数在一个地方传递
○子类的所有实例都可以给继承下来的属性赋不一样的值
●缺点:
○父类的原型上的方法没有继承下来


  // 父类
    function Person(name, age) {
        this.name = name
        this.age = age
    }
    Person.prototype.play = function() {
        console.log('玩游戏')
    }
    // 子类
    function Student(classRoom, name, age) {
        this.classRoom = classRoom
        // 实现继承
        Person.call(this, name, age)
    }
    const s = new Student(2114, 'Jack', 18)
    console.log(s)
    const s2 = new Student(2115, 'Rose', 20)
    console.log(s2)


复制代码

组合继承
●核心: 把原型继承和借用构造函数继承放在一起使用
●优点:
○都能继承下来
○属性在自己身上, 每一个子类实例继承的属性值都可以不一样
●缺点:
○子类的原型上多了一套属性


<script>
    // 父类
    function Person(name, age) {
        this.name = name
        this.age = age
    }
    Person.prototype.play = function() {
        console.log('玩游戏')
    }
    // 子类
    function Student(classRoom, name, age) {
        this.classRoom = classRoom
        // 借用继承
        // 目的: 把属性继承在自己身上
        Person.call(this, name, age)
    }
    // 原型继承
    // 目的: 继承父类原型上的方法
    Student.prototype = new Person()
    // 创建子类的实例
    const s = new Student(2114, 'Rose', 20)
    console.log(s)
</script>


复制代码

ES6类继承
●类的继承是ES6中提出的一种继承方式
●这个继承有了语法的规定,必须要按照这样的方式来继承
●类的继承的实现: 两个步骤实现继承
○书写子类的时候, 加上 extends 关键字
■class 子类 extends 父类 {}
■目的: 继承父类原型上的方法
○在子类的 constructor 内书写 super()
■super(实参)
■目的: 继承父类的属性
●注意:
○必须要书写 super 和 extends
○在子类的 constructor 内 super 必须写在 this.xxx 的前面(最前面)
●父类可以是构造函数,但是子类不能的构造函数因为extends和super关键字就是给类设计的


<script>
    // 父类
    class Person {
        constructor(name, age) {
            this.name = name
            this.age = age
        }
        play() {
            console.log('玩游戏')
        }
    }
    // 父类
    // function Person(name, age) {
    //   this.name = name
    //   this.age = age
    // }
    // Person.prototype.play = function () { console.log('玩游戏') }
    // 子类
    class Student extends Person {
        constructor(classRoom, name, age) {
            super(name, age)
            this.classRoom = classRoom
        }
        study() {
            console.log('学习')
        }
    }
    const s = new Student(2114, 'Jack', 18)
    console.log(s)
    class Teacher extends Person {
        constructor(gender, name, age) {
            super(name, age)
            this.gender = gender
        }
    }
    const t = new Teacher('男', 'Jack', 20)
    console.log(t)
</script>


复制代码

文章底部扫码,免费领取web前端资料大礼包!

拷贝继承
●利用 for in 循环遍历对象
●把所有的内容复制一份放在子类的原型上


   // 书写 for in 循环的时候, 不光可以遍历到对象自己身上的属性, 也可以遍历到原型上的属性
    // 父类
    function Person(name, age) {
      this.name = name
      this.age = age
    }
    Person.prototype.sayHi = function () { console.log('hello world') }

    // 创建一个父类的实例
    // const p = new Person('Jack', 18)
    // console.log(p)
    // for (let k in p) {
    //   console.log(k)
    // }

    // 子类
    function Student(gender, ...arg) {
      this.gender = gender

      // 创建一个父类的实例
      const p = new Person(...arg)
      // 利用 for in 循环继承
      for (let k in p) {
        // 随着循环, k 分别是 name age 和 sayHi
        Student.prototype[k] = p[k]
      }
    }

    const s = new Student('男', 'Jack', 18)
    console.log(s)
    console.log(s.name)
    const s2 = new Student('女', 'Rose', 20)
    console.log(s2)
    console.log(s2.name)


复制代码

寄生式继承

   /*
      寄生式继承1

    */

    // 父类
    function Person(name) {
      this.name = name
    }
    Person.prototype.sayHi = function () { console.log('hello world') }

    // 子类
    //   构造函数内不要写 return
    function Student() {
      // 直接在子类里面 return 一个父类的实例
      const p = new Person('Jack')
      return p
    }

    // 创建一个子类的实例
    // 看似得到的是 Student 的实例, 但是其实得到的还是 Person 的实例
    const s = new Student()
    console.log(s)
    
    
    
       /*
      寄生式继承2 - 对寄生式继承1 的 改造
    */

    // 父类
    function Person(name) {
      this.name = name
    }
    Person.prototype.sayHi = function () { console.log('hello world') }

    // 子类
    //   构造函数内不要写 return
    function Student(gender) {
      this.gender = gender
    }

    // 寄生一下 父类的原型
    // Student的原型指向 Person的原型
    Student.prototype = Person.prototype

    // 创建一个子类的实例
    // Student 自己没有原型使用了, 直接使用 Person 的原型
    const s = new Student('男')
    console.log(s) 
    
    
    
        // 寄生式组合继承

    // 父类
    function Person(name, age) {
      this.name = name
      this.age = age
    }
    Person.prototype.sayHi = function () { console.log('hello world') }


    // 实现继承
    //   借助一个第三方构造函数
    function Third() {}
    //   第三方构造函数去继承 父类
    //   利用寄生继承的方式来实现
    // 第三方的 原型 指向 父类的原型
    Third.prototype = Person.prototype
    // 将来我使用第三方创建实例的时候
    const t = new Third()

    // 子类
    function Student(...arg) {
      // 利用 call 继承
      Person.call(this, ...arg)
    }
    // 子类去想办法继承第三方的内容
    //   利用原型继承去继承第三方内容
    //   子类的原型指向第三方的实例
    Student.prototype = new Third()
    const s = new Student('Jack', 18)
    console.log(s)


    // 利用了一个自执行函数
    // 自执行函数, 不需要名字的函数
    ;(function () {
      var a = 100
      console.log('你好 世界')
    })()


    // 子类
    function Student(gender, ...arg) {
      this.gender = gender

      Person.call(this, ...arg)
    }

    // 把 第三方内容 放在自执行函数内
    (function () {
      function Third() {}
      Third.prototype = Person.prototype
      Student.prototype = new Third()
    })()

    const s = new Student('男', 'Jack', 18)
    console.log(s)



复制代码

文章底部扫码,免费领取web前端资料大礼包!

冒充式继承


    /*
      冒充继承
        + 利用了一个浅拷贝 + 寄生继承
    */

    // 父类
    function Person(name, age) {
      this.name = name
      this.age = age
    }
    Person.prototype.sayHi = function () { console.log('hello world') }

    const p = new Person('Jack', 18)

    // 寄生继承
    function Student(gender) {
      this.gender = gender

      // 创建完毕实例以后, 拷贝一个父类的实例
      Object.assign(this, p)
    }
    Student.prototype = Person.prototype

    const s = new Student('男')


    console.log(s)


 

 如果上面的文章看着比较枯燥,点击下面的链接直接观看:

千锋教育JavaScript全套视频教程(10天学会Js,前端javascript入门必备)

 

 也可以扫码直接观看视频哦!绝对的干货满满,更多精彩视频B站搜索“千锋教育” 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值