js实现继承的7种方法

116 阅读4分钟

`(1)类的创建,

 然后在构造函数中的prototype中增加属性和方法,构造函数中的普通函数会直接执行

特别要注意在构造函数的prototype中书写的方法是在实例化对象的__proto__=构造函数.prototype 所以可以直接调用
所有实例化对象通过原型链的方式可以共享构造函数prototype中的方法,

构造函数中的其他语句依然是像普通语句一样顺序执行, this一定要配合new来使用,顺序执行,开辟了一个空间,让构造函数中的this指向新开辟的空间,顺序执行构造函数,然后给新的空间添加方法和属性.`
   function Animal(name){
      this.name=name
      this.giao
      this.sex=function () {
        console.log(1);
      }
      this.size=()=>{
        console.log(12);
      }
    }
    // Animal()//这样子相当于在执行语句的时候给window添加方法和属性
    // console.log(size());
    Animal.prototype.giao=function(){
      return console.log('giao');
    }
    var x= new Animal()
    x.__proto__=Animal.prototype  x.__protp__constructor就是Animal.prototype中的constructor 指向这个函数本身 

prototype={
  1.自己添加的方法或属性
  2.constructor指向函数本身
  3.__proto__ 指向上一级构造函数的prototype
}
 1.原型链继承
function Cat(){
}
Cat.prototype=new Animal()
var cat =new Cat()
cat=  {
  __proto__=Cat.prototype= {
    name,
    sex,
    size,
    __proto__=Animal.prototype={
      giao,
      constructor,
      __proto__=Object.prototype={
        call,
        bind,
        apply,
        constructor,
        __proto__:null
      }
    }
  }
}
console.log(cat.__proto__.__proto__.giao())
2.构造继承 :使用父类的构造函数来增强子类实例,等于是赋值父类的实例属性给子类
function Cat(name){
  Animal.call(this);
  this.name=name
}
var cat= new Cat()
cat ={
  name,
  size,
  sex,
  __proto__=Cat.prototype={
    constructor: Cat,
    __proto__=Object.prototype={
        call,
        bind,
        apply,
        constructor,
        __proto__:null
      }
  }
}
优点:可以多继承,缺点:不能继承父类构造函数的原型对象,所以破坏了原型链继承的完整性
(3)组合继承:相当于构造函数和原型链继承的组合体,通过调用父类的狗奥,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数的复用
function Cat(name){
  Animal.call(this)
  this.name=name
}
Cat.prototype=new Animal()
Cat.prototype.constructor=Cat
var cat=new Cat()
cat ={
  name,
  sex,
  size,
  __proto__=Cat.prototype={
    name,size,sex,
    constructor:Cat(),
    __proto__=Object.prototype
  }

}
console.log(cat);
特点:既可以实现多继承,也可以继承父类的原型对象中的数据,但是会在__proto__中也生成一份实例,造成了内存的浪费
var cat=new Cat()
console.log(cat);
(4)原型式继承
基本想法:借助原型可以基于已有的对象创建新对象,同时还不必须因此创建自定义的类型,
function object(obj){
  function F(){
    F.prototype=obj
    return new F()
  }
}
var cat = new Cat()
我觉得没啥用,父类的引用属性会被所有子类实例共享,因为父类的引用的浅赋值
  (4)寄生组合继承,使用原型式继承获得一个目标对象的浅复制,然后增强这个浅复制的能力
  本质上和原型式继承没有任何区别,只不过可以多添加一些方法和属性
  function createAnnther(obj){
    var clone=object(obj)
    clone.color=function(){
      console.log('giao');
    }
    return clone
  }
最完美的继承
原型式方法
function object(obj){
  function F(){}
  F.prototype=obj
  return new F() //返回的式F的实例对象 ,实例对象的__proto__指向的是obj
}
//寄生式方法
function inherit(theFatherFunction,theSonFunction){
  var prototype=object(theFatherFunction.prototype)
  console.log(prototype);
  //复制了父亲的原型方法,得到拥有__proto__指向父亲prototype的实例对象
  prototype.constructor=theSonFunction// 改变constructor的指向,指向儿子构造函数
  theSonFunction.prototype=prototype //得到了父亲方法的完美儿子构造函数
}
function Parent(name){
  this.name=name
  this.height=function(){
    console.log('giaogiao');
  }
}
Parent.prototype.getName=function(){
  console.log(this.name);
}
var xx=new Parent()
console.log(xx);
function Child(name,age){
  Parent.call(this,name)
  this.age=age
}
inherit(Parent,Child)
var son=new Child()
console.log(son);

    **直观来看,完美的继承,
其一: 要实现子类构造函数要继承父类构造函数的this指向的属性和方法,  而借用call来构造继承,可以满足这一需求,且还可以多继承
其二: 要实现子类构造函数要继承父类构造函数的原型对象中的方法,而用此处用原型链继承,有问题,不能实现多继承,且造成了,内存狼内,而__proto__=prototype中的constructor会任然指向父类构造函数,所以此处用原型式继承,可以继承父类的原型对象,运用寄生的手段改变constructot的指向,可以实现父类原型对象的完美继承
其三:还有不完善的地方,没有实现多父类原型方法的继承,可以用过代码修改**


(7)
// es6中的class继承
  // es6引入class关键字,class可以通过extends关键字实现继承,还可以以通过static关键字定义静态类方法,这比es5的通过修改原型链实现继承,先将父类实例对象的属性和方法,加到this上卖
  class Person {
    constructor(name,age){
      this.name=name
      this.age=age
    }
    showName(){
      console.log(this.name);
    }
  }
  class Child  extends Person{
    constructor(name,age,salary) {
      super(name,age)//通过super调用父类的构造方法
      this.salary=salary
    }
    showGiao(){
      console.log('giao');
    }
  }
  var s1= new Child('giao1',23,10000)
  console.log(s1);