详解js继承

183 阅读2分钟

1.普通继承

function Parent(name){
  this.name = name
}
​
function Son(age,name) {
  //!在父构造函数中给子类实例添加属性
  
    this.age  =age
}
​
Son.prototype= new Parent("bang")
Son.prototype.constructor = Son//使得parent的实例像一个原型空间 
let s1 = new Son(1,'bang')
​
​

缺点 无法传给父类的name属性

2.prototype继承

function Parent(name){
  this.name = name
}
​
function Son(age,name) {
  //!在父构造函数中给子类实例添加属性
  
    this.age  =age
}
​
Son.prototype= Parent.prototype
Son.prototype.constructor = Son//使得parent的实例像一个原型空间 
let s1 = new Son(1,'bang')
​
​

缺点

无法传给父类的name属性

无法读取parent的私有属性 只能读取原型对象属性

3.构造函数+修改protytpe

function Parent(name){
  this.name = name
}
​
function Son(age,name) {
  //!在父构造函数中给子类实例添加属性
  Parent.call(this,name) //扩展s1这个对象上的属性 本来只有age一个属性 现在多一个name属性
    this.age  =age
}
​
Son.prototype= new Parent("bang") //这一次完全没必要
Son.prototype.constructor = Son//使得parent的实例像一个原型空间 
let s1 = new Son(1,'bang')
​

可以实现读取parent的私有属性但是调用啦两次parant函数 第一次完全没必要

4.构造函数+修改protytpe

function Parent(name){
  this.name = name
}
​
function Son(age,name) {
  //!在父构造函数中给子类实例添加属性
  Parent.call(this,name) //扩展s1这个对象上的属性 本来只有age一个属性 现在多一个name属性
    this.age  =age
}
​
Son.prototype= Parent.prototype
Son.prototype.constructor = Son//使得parent的实例像一个原型空间 
let s1 = new Son(1,'bang')
​

缺点 Son.prototype.constructor = Son 这一个会让parent的 parent.prototype.constructor也为son不符合逻辑

5.寄生组合

采用中间函数的形式

function Parent(name){
  this.name = name
}
​
function Son(age,name) {
  //!在父构造函数中给子类实例添加属性
  Parent.call(this,name) //扩展s1这个对象上的属性 本来只有age一个属性 现在多一个name属性
    this.age  =age
}
function _extends(parent,son){
  function middle(){
    this.constructor = son //this就是middle实例就是son.prototype
  }
​
  middle.prototype = parent.prototype
  return new middle()
}
Son.prototype=_extends(Parent,Son)
let s1 = new Son(1,'bang')
console.log(s1)

主要是加一个Miiddle层解决Son.prototype= Parent.prototype导致修改Son.prototype.constructor = Son 时候 parent.prototype.constructor也为son的问题 加一层这个middle的实例的constructor 就指向Son,parent的不变 ,只是原型链长啦一节

_extends写法很麻烦,es6提供了object.create()函数

function Parent(name){
  this.name = name
}
Parent.prototype.cname = 'parent的protytpe'
function Son(age,name) {
  //!在父构造函数中给子类实例添加属性
  Parent.call(this,name) //扩展s1这个对象上的属性 本来只有age一个属性 现在多一个name属性
    this.age  =age
}
function _extends(parent,son){
  function middle(){
    this.constructor = son //this就是middle实例就是son.prototype
  }
​
  middle.prototype = parent.prototype
  return new middle()
}
Son.prototype= Object.create(Parent.prototype)
Son.prototype.constructor = Son
//Son.prototype=_extends(Parent,Son)
let s1 = new Son(1,'bang')
console.log(s1)
​
​

object.create()就是创建一个空函数然后把他的prototype=父函数的prototype,然后返回实例 和extends区别就是没有绑定constructor 让middle实例看上去更像一个原型对象空间

\