JS中的继承以及不同的方式

继承

  • 继承是和构造函数相关的一个应用
  • 是指,让一个构造函数去继承另一个构造函数的属性和方法
  • 所以继承一定出现在 两个构造函数之间
  • 就是同类之间的继承,所谓的基础其实就是为了减少代码量
继承的作用
  • 我们之前说,在我们书写构造函数的时候,为了解决一个函数重复出现的问题

  • 我们把构造函数的 方法 写在了 prototype

  • 这样,每一个实例使用的方法就都是来自构造函数的 prototype

  • 就避免了函数重复出现占用内存得到情况

  • 那么,如果两个构造函数的 prototype 中有一样的方法呢,是不是也是一种浪费

  • 所以我们把构造函数 prototype 中的公共的方法再次提取

  • 我们准备一个公共的构造函数,让构造函数的 __proto__ 指向这个公共的构造函数的 prototype

常见的继承方式
  • 我们有一些常见的继承方式来实现和达到继承的效果

  • 我们先准备一个父类(也就是要让别的构造函数使用我这个构造函数的属性和方法)

    function Person() {
        this.name = 'Jack'
    }
    
    Person.prototype.sayHi = function () {
        cosnole.log('hello')
    }
    
  • 这个 Person 构造函数为父类

  • 让其他的构造函数来继承他

  • 当别的构造函数能够使用他的属性和方法的时候,就达到了继承的效果

拷贝继承

就是把一个对象里面的属性赋值给另一个对象.

例如把下面的对象拷贝一遍:

let obj = {
            name: '轩哥',
            like: '喜欢打游戏'
        }

有三种实现方式(浅拷贝):

第一种方式: 使用for in 循环遍历

let obj2 = {}
for(let key in obj){
    obj2[key] = obj[key]
   } 

第二种方式:使用扩展运算符

let obj2 = {
            ...obj
        }

第三种方式:使用assign方法

let obj2 = Object.assign({}, obj)
    console.log(obj2)
原型继承

在这里插入图片描述

  • 原型继承,就是在本身的原型链上加一层结构

    function Student() {}
    Student.prototype = new Person()
    
  • 原型继承优缺点:

    优点:构造函数体内和原型上的都可以继承

    缺点:

    一个构造函数的内容,在两个位置传递参数

    继承来的属性不在子类实例的身上

​ 如果直接把父类构造函数的原型对象赋值给子类型的原型对象,设置在字类构造函数的原型上的方法,父类构造函数的实例化对象也可以使用,这样非常不合理

代码实例如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 父构造函数
        function Father(name, age){
            this.name = name
            this.age = age
        }
        Father.prototype.money = function(){
            console.log('一个小目标')
        }

        // 子构造函数
        // 构造函数存在一个原型链,其实可以利用原型链之间的关系实现继承
        function Son(name, age){
            this.name = name
            this.age = age
        }
        // 可以把父类构造函数的原型对象赋值给子类型的原型对象
        // 问题:如果这样做,设置在Son构造函数的原型上的方法,父类构造函数的实例化对象也可以使用,这样非常不合理
        Son.prototype = Father.prototype
        Son.prototype.love = function(){
            console.log('蹲牢房')
        }

        let s = new Son('张三', 18)
        s.money()
        s.love()

        console.log(Son.prototype)

        new Father('罗翔', 38).love()

    </script>
</body>
</html>

​ 所以我们可以把父类构造函数的实例化对象赋值给子类的构造函数的原型对象

在这里插入图片描述

代码示例如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 父构造函数
        function Father(name, age){
            this.name = name
            this.age = age
        }
        Father.prototype.money = function(){
            console.log('一个小目标')
        }

        // 子构造函数
        // 构造函数存在一个原型链,其实可以利用原型链之间的关系实现继承
        function Son(name, age){
            // this.name = name
            // this.age = age
        }

        // 把父类构造函数的实例化对象赋值给子类的构造函数的原型对象
        Son.prototype = new Father('张三', 18)
        Son.prototype.love = function(){
            console.log('谈👫🏻')
        }

        /*
            优点:构造函数体内和原型上的都可以继承

            缺点:
            + 一个构造函数的内容,在两个位置传递参数
            + 继承来的属性不在子类实例的身上
        */
        let s = new Son()
        s.money()
        s.love()

        console.log(s.name)

        console.log(s)

        
        
    </script>
</body>
</html>
借用构造函数继承
  • 把父类构造函数体借用过来使用一下而已

    function Student() {
      Person.call(this)
    }
    
  • 借用构造函数继承优缺点:

    优点:

    继承来的属性是在自己身上

    我们一个实例化过程在一个位置传递参数

    缺点:

    只能继承父类构造函数体内的内容

    父类原型上的内容不能继承

在这里插入图片描述

代码示例如下:

// 父类构造函数
        function Father(name, age){
            this.name = name
            this.age = age
        }
        Father.prototype.money = function(){
            console.log('一个小目标')
        }

        // 子构造函数
        function Son(name, age){
            Father.call(this, name, age)
        }

        let s = new Son('张三', 18)
        console.log(s)
        console.log(s.name)

        /*
            借用构造函数继承优缺点:
            优点:
            + 继承来的属性是在自己身上
            + 我们一个实例化过程在一个位置传递参数

            缺点:
            + 只能继承父类构造函数体内的内容
            + 父类原型上的内容不能继承
        */

组合继承
  • 就是把 原型继承借用构造函数继承 两个方式组合在一起

    function Student() {
      Person.call(this)
    }
    Student.prototype = new Person()
    
  • 组合继承的优缺点:

    优点:

    父类构造函数体内和原型上的内容都能继承

    继承下来的属性放在自己身上

    在一个位置传递所有的参数

    缺点:

    当你给子类添加方法的时候,实际上是添加在父类的实例身上

代码示例如下:

// 父类构造函数
        function Father(name, age){
            this.name = name
            this.age = age
        }
        Father.prototype.money = function(){
            console.log('一个小目标')
        }

        // 子构造函数
        function Son(name, age){
            Father.call(this, name, age)
        }
        Son.prototype = new Father()
        Son.prototype.love = function(){
            console.log('蹲牢房')
        }

        let s = new Son('张三', 18)
        console.log(s)
        s.money()
        
        new Father('罗翔', 38).money()
ES6 的继承
  • es6 的继承很容易,而且是固定语法

    // 下面表示创造一个 Student 类,继承自 Person 类
    class Student extends Person {
        constructor () {
            // 必须在 constructor 里面执行一下 super() 完成继承 
            super()
        }
    }
    
  • 这样就继承成功了

代码案例如下:

class Father{
            constructor(name, age){
                this.name = name
                this.age = age
            }
            money(){
                console.log('一个小目标')
            }
        }
        class Son extends Father{
            constructor(name, age, like) {
                // 注意点:super()这个函数必须要保证放在最前面,因为需要先改变this指向继承父类的属性(优先级高于自身)
                super(name, age)
                this.like = like
            }
        }
        let s = new Son('张三', 18, '咬人')
        console.log(s)
        s.money()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值