• JavaScript


    什么是继承 => 就是让一个对象使用了不属于自己的属性和方法

    继承的作用 => 将相关的构造函数之间的公共方法提取出来,放在一个公共的构造函数上,节省空间

    八种继承的方法:

    (本文栗子全部使用 Student 构造函数继承 Person 类)

    // 准备一个公共的被继承的构造函数
    function Person(name) {
      this.name = name || 'person'
      this.age = 18
    }
    
    Person.prototype.eat = function () {
      console.log('eatting')
    }

    此构造函数在 new Person 的时候会得到一个对象:

    {
        name: 'person',
        age: 18,
        __proto__: {
        eat: function () {},
        constructor: Person,
        __proto__: Object.prototype
        }
    }

    1、原型继承

      借助原型链

        /*
          一、原型继承
    
          function Student() {}
          Student.prototype = new Person
    
          将来我们 new Student 的时候会得到一个什么东西
          var s = new Student
          s = {
            __proto__: Student.prototype {
              name: 'person',
              age: 18,
              __proto__: Person.prototype {
                eat: function () {},
                __proto__: Object.prototype
              }
            }
          }
    
          优点: 使用简单,好理解
          缺点: 原型链多了一层,并且这一层没什么用
    
        */
    
        function Student() {
          this.name = 'lilei'
        }
        Student.prototype = new Person
        var s = new Student
        console.log(s)

    2、借用继承

      借用构造函数,使用 call 方法

        /*
          一、借用构造函数继承
    
          function Student() {
            // 这个 Student 函数里面的 this 指向谁? s
            // this 就是 s
            Person.call(this)
          }
    
          Person 是一个函数
            - 当函数和 new 连用的时候 this 指向实例
            - 普通调用 Person() this 指向 window
            - call 是在调用函数的时候直接强行改变 this 指向
    
          将来你 new Student 的时候
          {
            name: 'person',
            age: 18,
            __proto__: Student.prototype {
              constructor: Student,
              __proto__: Object.prototype
            }
          }
    
          优点: 直接把属性变成自己的了
          缺点: 没有父类原型上的东西
        */
    
        function Student() {
          Person.call(this)
        }
    
        var s = new Student()
        console.log(s)

    3、组合继承

      将原型继承和借用继承组合使用

          // 一、组合继承
    
          function Student() {
            Person.call(this)
          }
          Student.prototype = new Person
    
          // 将来我们 new Student 的时候
          //   - 对象里面的属性由借用来的 Person 来
          //   - 原型由 new Person 来
          // {
          //   name: 'person',
          //   age: 18,
          //   __proto__: new Person {
          //     name: 'person',
          //     age: 18,
          //     __proto__: Person.prototype {
          //       eat: function () {},
          //       constructor: Person,
          //       __proto__: Object.prototype
          //     }
          //   }
          // }
    
          // 优点: 属性继承来变成自己的,原型也继承过来了
          // 缺点: 第一层原型没用,继承的原型多走一步

    4、拷贝继承

      使用 for in 循环,将父类的属性和方法放到子类的 prototype 里面

        /*
          一、拷贝继承
    
    
          function Student() {
            var p = new Person
            for (var key in p) {
              Student.prototype[key] = p[key]
            }
          }
    
          将来我们 new Student 的时候
          {
            __proto__: Student.prototype {
              name: 'person',
              age: 18,
              eat: function () {},
              constructor: Student,
              __proto__: Object.prototype
            }
          }
    
          优点: 属性和方法都继承来放在我自己的原型上了
          缺点: for in 循环,相当消耗性能的一个东西
        */
    
        function Student() {
          var p = new Person
          for (var key in p) {
            Student.prototype[key] = p[key]
          }
        }
        var s = new Student
        console.log(s)

    5、寄生式继承

      new 一个 Person 函数

        /*
          一、寄生继承
    
          function Student() {
            var p = new Person
            return p
          }
    
          将来当你 new Student  的时候
          得到的是什么,但是我得到的是 Person 的实例
    
          优点: 完美的继承了属性和方法
          缺点: 根本没有自己的东西了
        */
    
        function Student() {
          this.gender = '男'
          var p = new Person
          return p
        }
    
        Student.prototype.fn = function () {}
        var s = new Student
        console.log(s)

    6、寄生式组合继承1

      组合了 借用继承+寄生式继承的一部分(寄生prototype)

        /*
          一、寄生式组合继承1
    
          function Student() {
            Person.call(this)
          }
          Student.prototype = Person.prototype
    
          将来我们 new Student 的时候会得到
          {
            name: 'person',
            age: 18,
            __proto__: Person.prototype {
              eat: function () {},
              constructor: Person,
              __proto__: Object.prototype
            }
          }
    
          // 我没有自己的原型,我想自己的原型上添加成渝啊你的时候,就是向父类的原型上添加
    
          有点: 原型的东西不需要多走一步
          缺点: 没有自己的原型
        */
    
        function Student() {
          Person.call(this)
        }
        Student.prototype = Person.prototype
    
        Student.prototype.fn = function () {}
    
    
        var s = new Student
        console.log(s)
        console.log(Person.prototype)

    7、寄生式组合继承2

      组合了 借用继承+原型继承+寄生式继承的一部分(寄生prototype)

        /*
          一、寄生式组合继承2
    
          function Student() {
            Person.call(this)
          }
          (function () {
            function Abc() {}
            Abc.prototype = Person.prototype
            Student.prototype = new Abc
          })()
    
          将来 new Student 的时候会得到
          {
            name: 'person',
            age: 18,
            __proto__: new Abc {
              __proto__: Person.prototype {
                eat: function () {}
              }
            }
          }
    
          优点: 属性继承来是自己的,方法也继承来了,组合式继承的中间哪个环节多余的属性没有了
          缺点: 就是多了一个 空环,导致我访问继承的方法的时候要多走一步
        */
    
        function Student() {
          Person.call(this)
        }
        (function () {
          function Abc() {
            this.constructor = Student
          }
          Abc.prototype = Person.prototype
          Student.prototype = new Abc
        })()
    
      var s = new Student
      console.log(s)
    
    
        // function Student() {
        //   Person.call(this)
        // }
        // // 为什么要一个自执行函数? =》 为了保护私有变量不去污染全局
        // (function () {
        //   function Abc() {}
        //   Abc.prototype = Person.prototype
        //   Student.prototype = new Abc
        // })()
    
        // function Student() {
        //   Person.call(this)
        // }
        // // 为什么要一个自执行函数? =》 为了保护私有变量不去污染全局
        // function Abc() {}
        // Abc.prototype = Person.prototype
        // Student.prototype = new Abc
        // // 将来我 new Abc 的时候
        // {
        //   __proto__: Person.prototype {
        //     eat: function () {}
        //   }
        // }
    
        // // 将来我new Student 的时候
        // {
        //   __proto__: new Abc {
        //     __proto__: Person.prototype {
        //       eat: function () {}
        //     }
        //   }
        // }

    8、混搭式继承

      组合了 借用继承+for in 继承父类的prototype

        /*
          一、混搭式继承
    
          function Student() {
            Person.call(this)
          }
          (function () {
            var obj = Person.prototype
            for (var key in obj) {
              Student.prototype[key] = obj[key]
            }
          })()
    
          将来我们 new Student 的时候
          {
            name: 'person',
            age: 18,
            __proto__: Student.prototype {
              constructor: Student,
              eat: function () {},
              __proto__: Object.prototype
            }
          }
    
          优点: 属性原型都有了,没有多余的空环,constructor 直接指向自己
          缺点: for in循环,没有缺点
        */
    
        function Student() {
          Person.call(this)
        }
        (function () {
          var obj = Person.prototype
          for (var key in obj) {
            Student.prototype[key] = obj[key]
          }
        })()
    
        Student.prototype.fn = function () {}
    
        var s= new Student
    
        console.log(s)
        console.log(Person.prototype)
  • 相关阅读:
    gc buffer busy/gcs log flush sync与log file sync
    给Oracle年轻的初学者的几点建议
    Android 编程下帧动画在 Activity 启动时自动运行的几种方式
    Android 编程下 Touch 事件的分发和消费机制
    Java 编程下 static 关键字
    Java 编程下 final 关键字
    Android 编程下模拟 HOME 键效果
    Why Are Thread.stop, Thread.suspend, Thread.resume and Runtime.runFinalizersOnExit Deprecated ?
    Extjs4 大型项目目录结构重构
    [转]SQLServer 2008 允许远程连接的配置方法
  • 原文地址:https://www.cnblogs.com/yummylucky/p/10565208.html
Copyright © 2020-2023  润新知