乐趣区

关于javascript:js继承

1. 原型链继承:

 // 原型链继承
  function Super(){this.color=['red','yellow','black']
  }

  function Sub(){}
  // 继承了 color 属性 Sub.prototype.color=['red','yellow','black']
  Sub.prototype=new Super()

  // 创立实例 instance1.__proto__.color
  const instance1=new Sub()
  const instance2=new Sub()
  console.log(instance1.__proto__.color===instance2.__proto__.color) //true

原型链继承问题:
1. 实例之间会共享援用类型的值
2. 创立子类实例(instance1)时,没有方法向超类型(Super)的构造函数中传递参数

2. 借用构造函数

  function Super(name,age){
    this.name=name
    this.age=age
    this.color=['red','yellow','black']
    this.sayHi=function(){console.log('hi')
    }
    console.log(this)
  }
  function Sub(){Super.apply(this,arguments)
    this.height=180
  }
  // 创立实例 
  var instance1=new Sub('ccdida',25)
  var instance2=new Sub('piaopiao',25)
  instance1.sayHi()

Super 和 Sub 中的 this 都指向 instance 实例。前者因为 Apply 扭转了 this 指向,后者则是因为 new 操作。
所以每个实例都就有了属于本人的属性,不会相互影响。

构造函数继承问题:
办法只能定义在构造函数中,函数无奈复用

3. 组合继承

  // 属性
  function Super(name,age){
    this.name=name
    this.age=age
    this.color=['red','yellow','black']
  }
  // 超类办法
  Super.prototype.sayHi=function(){console.log('hi')
  }
  function Sub(name,age,height){
    // 继承属性
    Super.apply(this,arguments)
    this.height=height
  }
  // 继承办法(重写子类原型对象)
  //1. 通过原型链继承了办法:Sub.prototype.__proto__===Super.prototype
  //2.Sub.prototype:{name: undefined, age: undefined, color: Array(3)}
  //3.Sub 原型对象曾经被笼罩,当初只能从原型链上找 constructor,指向 Super
  Sub.prototype=new Super()
 //constructor 从新指向 Sub
  Sub.prototype.constructor=Sub
  console.log(Sub.prototype)//{name: undefined, age: undefined, color: Array(3), constructor: ƒ}
  // 定义属于子类的办法
  Sub.prototype.sayHello=function(){console.log('sayHello')
  }

  // 创立实例 
  var instance1=new Sub('ccdida',25,180)
  var instance2=new Sub('piaopiao',24,170)
 
  console.log(instance1)

  console.log(instance1.__proto__===Sub.prototype)//true
  console.log(instance1.__proto__.__proto__===Super.prototype)//true
  console.log(Sub.prototype.__proto__===Super.prototype)//true
  instance1.sayHi() //hi

总结:
1. 通过构造函数让实例领有属于本人的属性(name,age,color 等),不会相互影响
2. 通过原型链继承了父类的办法,实现了函数复用

4. 原型式继承

 function object(o){function F(){}
    //F.prototype={name:'ccdida',friends:['shelly','Bob']}
    F.prototype=o
    // new F() 
    // F 是个构造函数,返回 F 的实例:1.this 此时用不上 2. 将实例的__proto__指向 F.prototype.
    // 即返回了一个实例,其__proto__指向{name:'ccdida',friends:['shelly','Bob']}
    return new F()}
  var person={
    name:'ccdida',
    friends:['shelly','Bob']
  }
  var person1=object(person)
  var person2=object(person)
  //object 函数相当于实现了 Object.Create 的性能
  console.log(person1.__proto__===person) //true 
  person2.friends.push('shlimy')
  console.log(person1.friends)// ["shelly", "Bob", "shlimy"]

毛病:援用类型值会共享
值类型不会共享,因为在扭转值类型时,相当于给本人增加了属性。
当去批改援用类型的某个值时,是在批改__proto__中的对象。但如果间接给援用类型赋值,那也和值类型一样,是给本人减少了属性

person2.friends={}
  console.log(person1.friends)// ["shelly", "Bob"]
  person2.name='123'
  console.log(person1.name)// ccdida

5. 寄生式继承

 var person={
    name:'ccdida',
    friends:['shelly','Bob']
  }
  function createAnother(original){
    //clone.__proto__===original
    var clone=Object.create(original)
    // 加强对象,增加属于本人的办法
    clone.sayHi=function(){console.log('hi')
    }

    return clone

  }
  var person1=createAnother(person)
  var person2=createAnother(person)
  person1.friends.push('shmily')
  console.log(person2.friends)//["shelly", "Bob","shmily"]
  person1.sayHi() //hi

毛病:不能做到函数复用,援用类型数据仍然共享

原型式继承:基于已有的对象(原型对象)创立新对象(实现 Object.create())
寄生式继承:创立一个用于封装继承过程的函数(实现 Object.create()), 同时以某种形式加强对象(比方增加办法)

6. 寄生组合式继承

后面的组合继承有个毛病:每次创立实例时都会调用两次超类办法,一次是通过 new 设置原型的时候,另一次是用 apply 执行的时候

其实下面打印的时候应该有看到,在通过 new 继承原型时,执行了构造函数 Super,所以 Sub.prototype 中有 name 属性
在通过 apply 执行构造函数时,instance 实例上也有了 name 属性.

所以是不够完满吗?此刻的我还不懂 === 反正寄生组合式继承能够解决这个问题

所谓寄生组合式继承:通过借用构造函数来继承属性(apply),通过原型链的混成模式来继承办法(Object.create)

思路:不须要为了指定子类型的原型而调用超类型的构造函数(我了解为就是不须要显示的 new 操作),通过下面的寄生式继承形式来继承超类型的原型即可。

 // 寄生组合继承: 这个过程既实现了继承,又没有去调用 Super
  function inheritPrototype(Sub,Super){
    //subPrototype.__proto__=Super.prototype
    var subPrototype=Object.create(Super.prototype)
    //subPrototype.constructor=Sub
    subPrototype.constructor=Sub
    // 相当于 subPrototype 有__proto__和 constructor 两个属性
    // 即://Sub.prototype.__proto__===Super.prototype
    //Sub.prototype.constructor=Sub
    Sub.prototype=subPrototype
    
  }
  function Super(name){this.name=name}
  Super.prototype.sayHi=function(){console.log(this.name)//ccdida
  }
  function Sub(name){Super.call(this,name)
  }
  inheritPrototype(Sub,Super)

  Sub.prototype.sayHello=function(){console.log('sayHello')
  }

  var instance1=new Sub('ccdida')
  // instance1.sayHi()
  console.log(instance1.__proto__)
  console.log(instance1.__proto__.__proto__)

总结:
实例通过 Super.call(this,name)拿到 Super 中的属性(这些属性属于实例自身,不会被共享)

子类通过 Object.create,让子类的原型对象的隐式原型(proto)指向父类的原型对象,实现办法的继承(可复用)

撒花~~~

退出移动版