https://files-cdn.cnblogs.com/files/yummylucky/zhifu.bmp

支付宝

https://files-cdn.cnblogs.com/files/yummylucky/WeChat.bmp

微 信

JavaScript - 8种继承方式 (全)

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

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

 

八种继承的方法:

(本文栗子全部使用 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)

 

posted @ 2019-03-20 15:29  kiss雪夜  阅读(334)  评论(0编辑  收藏  举报