继承的六种方式

一、原型链继承

思想:利用原型让一个引用类型继承另一个引用类型的属性和方法
构造函数、原型和实例之间的关系:每个构造函数都有一个原型对象,原型对象都包括一个指向构造函数的指针,实例都包含一个指向原型对象的内部指针

function SuperType(){
  this.property = true;
}
SuperType.prototype.getSuperValue = function(){
  return this.property;
}
function SubType(){
  this.Subproperty = false;
}
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
  return this.property;
}
var instance = new SubType();
console.log(instance.getSuperValue());  //true

所有函数的默认原型都是Object的实例
确定原型和实例之间的关系:
1、实例 instanceof 原型 //true or false
2、原型.prototype.isPrototypeOf(实例) //true or false
在构造函数而不是原型对象中定义属性和方法(包含引用类型值的原型属性会被所有实例共享)
在创建子类型的实例时不能向超类型的构造函数中传递参数

二、构造函数继承

思想:在子类型构造函数的内部调用超类型的构造函数

function SuperType(){
  this.colors = ['red','yellow','blue'];
}
function SubType(){
  SuperType.call(this);  //继承了SuperType  也可用apply()方法
}
var instance = new SubType();
instance.colors.push('black');
console.log(instance.colors); //['red','yellow','blue','black']
var instance1 = new SubType();
console.log(instance1.colors);//['red','yellow','blue']

借用构造函数继承可以在子类型构造函数中向超类型构造函数传递参数:

function SuperType(name){
  this.name=name;
}
function SubType(){
  SuperType.call(this,'zhangsan'); //继承了SuperType 同时传递参数
  this.age=29;   //实例属性
}
var instance = new SubType();
console.log(instance.name);  //zhangsan
console.log(instance.age);  //29

缺点:方法在构造函数中定义则用不到函数复用,在超类型原型中定义的方法对子类型不可见,即所有类型都只能用构造函数模式

三、组合继承(原型链和构造函数)

思想:使用原型链实现对原型属性和方法的继承,通过使用构造函数实现对实例属性的继承

function SuperType(name){
  this.name=name;
  this.colors = ['red','yellow','blue'];
}
SuperType.prototype.sayName = function(){
  console.log(this.name); 
}
function SubType(name,age){
  //继承属性
  SuperType.call(this,name); //第二次调用
  this.age = age;
}
//继承方法
SubType.prototype = new SuperType();  //第二次调用
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
  console.log(this.age);
}

var instance1= new SubType('zhangsan',23);
instance1.colors.push('black');
console.log(instance1.colors);
//["red", "yellow", "blue", "black"]
instance1.sayName();  //zhangsan
instance1.sayAge(); //23

var instance2 = new SubType('lisi',28);
console.log(instance2.colors);//["red", "yellow", "blue"]
instance2.sayName();//lisi
instance2.sayAge();//28

SuperType构造函数定义了两个属性:name和colors,其原型定义了一个方法sayName();SubType构造函数在调用SuperType构造函数是传入了name参数,定义了自己的属性age;将SuperType的实例赋值给SubType的原型,在此原型上定义了方法sayAge();即可让俩个不同SubType实例分别拥有自己的属性包括colors,使用相同的方法。

四、原型式继承

必须要有一个对象作为另一个对象的基础

var person = {
    name:'zhangsan',
    friends:['A','B','C']
}
var anotherPerson =Object.create(person);
anotherPerson.name='lisi';
anotherPerson.friends.push('D');
var yetAnotherPerson=Object.create(person);
yetAnotherPerson.name='huahua';
yetAnotherPerson.friends.push('E');
console.log(person.friends);  // ["A", "B", "C", "D", "E"]

create()接收两个参数:用作新对象原型的对象,为新对象定义属性的对象(可选)

var person = {
    name:'zhangsan',
    friends:['A','B','C']
}
var anotherPerson =Object.create(person,{
 name:{
   value:'lisi'
 }
});
console.log(anotherPerson.name);  //lisi

包含引用类型值的属性始终都会共享相应的值就像使用原型模式一样。

五、寄生式继承

思想:创建一个仅用于封装继承过程的函数,该函数在内部以某种方式增强对象,最后再像真正是其做了所有工作一样返回对象

function createAnother(original){
  var clone = Object(original); //通过调用函数创建一个对象
  clone.sayHi=function(){//以某种方式来增强这个对象
    console.log('hi');
  };
  return clone;  //返回对象
}
var person={
  name:'zhangsan',
  friends:['A','B','C']
}
var anotherPerson=createAnother(person);
anotherPerson.sayHi();  //hi

Object()函数非必需,任何可返回新对象的函数均可,寄生式继承不能函数复用所以会降低效率

六、寄生组合式继承

通过借用构造函数继承属性,通过原型链的混成形式继承方法

function inheritPrototype(SubType,SuperType){
  var prototype = Object(SuperType.prototype);//创建对象
  prototype.constructor=SubType; //增强对象
  SubType.prototype=prototype;//加强对象
}
function SuperType(name){
  this.name=name;
  this.colors =['red','blue','yellow'];
}
SuperType.prototype.sayName=function(){
  console.log(this.name);
}
function SubType(name,job){
  SuperType.call(this.name);
  this.age=age;
}

inheritPrototype(SubType,SuperType);
SubType.prototype.sayAge=function (){
  console.log(this.age);
}
//ƒ (){ console.log(this.age);}

你可能感兴趣的:(继承的六种方式)