1. function Person (name,age,language){
  2. this.name = name;
  3. this.age = age;
  4. this.language = language;
  5. this.sleep = function (){
  6. console.log('im '+this.name+' im sleeping')
  7. }
  8. }
  9. Person.prototype.speak = function(){
  10. console.log('im '+this.name+' im speak '+this.language)
  11. }
  12. Person.prototype.eyes = 4

原型链继承

原理

将父类的实例作为子类的原型

  1. 子类.prototype = new 父类()
  1. function Chinese(province){
  2. this.province = province
  3. this.eat = function(){
  4. console.log('im '+this.language+',im eating')
  5. }
  6. }
  7. Chinese.prototype = new Person()
  8. Chinese.prototype.constructor = Chinese //修复constructor的指向
  9. //如果有 prototype 上的方法和属性,要放在这里之后
  10. Chinese.prototype.language = 'chinese'
  1. let gromy = new Chinese('吉林')

看下gromy都有什么?

image.png

  1. gromy.speak()
  2. VM5382:2 im undefined im speak chinese
  3. gromy.sleep()
  4. VM5278:6 im undefined im sleeping
  5. gromy.eat()
  6. VM6138:4 im chinese,im eating

所以子类的实例可以使用父类的方法,但是由于无法向父类传参数,所以 没有name

优点

  • 实现简单
  • 可以访问父类所有的方法

    缺点

  • 不能向父类的构造函数传参

  • 无法实现多继承

    使用

    想使用某个父类所有方法时使用

    构造函数继承

    原理

    在子类构造函数中通过 call 将父类的构造器中的内容合并

    1. function Chinese(name,age,language,province){
    2. this.province = province
    3. Person.call(this,name,age,language)
    4. this.eat = function(){
    5. console.log('im '+this.language+',im eating')
    6. }
    7. }
    8. Chinese.prototype.language = 'chinese'
    1. let gromy = new Chinese('gromy',18,'english')

    image.png
    属性,方法都合并过来了

    1. gromy.sleep()
    2. VM5659:6 im gromy im sleeping
    3. gromy.speak()
    4. VM5935:1 Uncaught TypeError: gromy.speak is not a function
    5. at <anonymous>:1:7
    6. gromy.eat()
    7. VM6178:5 im english,im eating

    父类在prototype上的speak() 并没有继承过来

    优点

  • 可以实现多继承(使用多个call)

  • 可向父类传参(实际是把属性在构造器中合并过来了)

缺点

  • 因为是合并过来的,所以每个子类的实例都是副本,影响性能
  • 不能继承父类 prototype 上的属性和方法

    使用

    想使用父类构造器中的属性时使用

    原型+构造器组合

    1. function Chinese(name,age,language,province){
    2. this.province = province
    3. Person.call(this,name,age,language)
    4. this.eat = function(){
    5. console.log('im '+this.language+',im eating')
    6. }
    7. }
    8. Chinese.prototype = new Person()
    9. Chinese.prototype.constructor = Chinese //修复constructor的指向
    10. //如果有 prototype 上的方法和属性,要放在这里之后
    11. Chinese.prototype.language = 'chinese'
    1. let gromy = new Chinese('gromy',18,'chinese','吉林')

    image.png

    1. gromy.sleep()
    2. VM6305:6 im gromy im sleeping
    3. gromy.speak()
    4. VM6305:10 im gromy im speak chinese
    5. gromy.eat()
    6. VM6307:5 im chinese,im eating
    7. gromy.eyes
    8. 4

    优点

  • 可以继承所有父类的属性和方法

  • 可传参数

缺点

  • 部分可实现多继承(call的部分)
  • 调用了两次父类构造,生成了两次实例

    原型+构造器优化

    组合的最大弊端是调用了两次父类的构造器,两次实例化

    1. function Chinese(name,age,language,province){
    2. this.province = province
    3. Person.call(this,name,age,language)
    4. this.eat = function(){
    5. console.log('im '+this.language+',im eating')
    6. }
    7. }
    8. Chinese.prototype = Person.prototype
    9. //Chinese.prototype.constructor = Chinese
    10. Chinese.prototype.language = 'chinese'
    1. let gromy = new Chinese('gromy',18,'chinese','吉林')

    image.png

    1. gromy.sleep()
    2. VM6422:6 im gromy im sleeping
    3. gromy.speak()
    4. VM6422:10 im gromy im speak chinese
    5. gromy.eat()
    6. VM6424:5 im chinese,im eating
    7. gromy.eyes
    8. 4

    but
    image.png
    gromy实例的 proto 指向了Person

    优点

  • 继承了所有父类的属性和方法

  • 避免了组合继承两次实例化的缺点

    缺点

  • 由于子类直接被赋值了父类的prototype,所以子类的实例的 proto 指向了父类

原型+构造器优化(使用Object.assign())

Object.assign() 是使用现有的对象来提供新创建的对象的 会将原型作用在实例的 proto

  1. function Chinese(name,age,language,province){
  2. this.province = province
  3. Person.call(this,name,age,language)
  4. this.eat = function(){
  5. console.log('im '+this.language+',im eating')
  6. }
  7. }
  8. Chinese.prototype = Object.assign(Person.prototype) //核心
  9. Chinese.prototype.constructor = Chinese //核心
  10. Chinese.prototype.language = 'chinese'
  1. gromy.__proto__

image.png
gromy.proto === Chinese.prototype

优点

  • Object.assign()就是银弹

    缺点

  • 多继承怎么完全实现?

    es6的class

    1. class Person {
    2. constructor(name,age,language){
    3. this.name = name;
    4. this.age = age;
    5. this.language = language;
    6. this.sleep = function(){
    7. console.log('im '+this.name+' im sleeping')
    8. }
    9. }
    10. speak(){
    11. console.log('im '+this.name+' im speak '+this.language)
    12. }
    13. }
    1. class Chinese extends Person{
    2. constructor(name,age,language,province){
    3. super(name,age,language)
    4. this.province = province
    5. this.eat = function(){
    6. console.log('im '+this.language+',im eating')
    7. }
    8. }
    9. }
    1. let gromy = new Chinese('gromy',18,'chinese','吉林')

    image.png

    1. gromy.sleep()
    2. VM6422:6 im gromy im sleeping
    3. gromy.speak()
    4. VM6422:10 im gromy im speak chinese
    5. gromy.eat()
    6. VM6424:5 im chinese,im eating
    7. gromy.eyes
    8. 4

    优点

  • 语法简单容易操作

    缺点

  • 浏览器对支持es6有限制