zoukankan      html  css  js  c++  java
  • 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)
  • 相关阅读:
    Linux下让一个程序开机自动启动
    Heartbeat高可用解决方案
    NFS文件共享
    清除系统日志的三个脚本
    nfs+rsync+inotify实现文件的实时同步
    安装配置rsync服务端
    shell中如何进行算术运算
    linux下查看账号密码的过期时间和设置时间
    配置Nginx作为web server详解
    [LeetCode] 398. Random Pick Index ☆☆☆
  • 原文地址:https://www.cnblogs.com/yummylucky/p/10565208.html
Copyright © 2011-2022 走看看