JS中实现继承

原型链继承

SubType.prototype = new SuperType();

注意点

//使用字面量添加新方法,会导致上一行代码无效
SubType.prototype = { 
 getSubValue : function (){ 
     return this.subproperty; 
 }, 
 someOtherMethod : function (){ 
     return false; 
 } 
}; 

单纯使用原型链继承会存在引用数据共用的问题。


借用构造函数继承

基础

function SubType(){ 
 //继承了 SuperType 
 SuperType.call(this); 
} 

可以实现传参

function SubType(name,age){ 
 //继承了 SuperType,同时还传递了参数
 SuperType.call(this, age); 
 //实例属性
 this.age = age; 
}

存在的问题是方法都在构造函数里面定义,而无法继承到SubType里面的方法,淡化了函数复用概念


组合继承

组合原型链和借用构造继承

function SubType(name, age){ 
 //继承属性
 SuperType.call(this, name); 
 
 this.age = age; 
} 

//继承方法
SubType.prototype = new SuperType(); 
//弥补因重写原型而失去的默认的 constructor 属性
SubType.prototype.constructor = SubType; 
//实现在原型链增加共用函数 达到函数复用
SubType.prototype.sayAge = function(){ 
 alert(this.age); 
}; 

这属于很常用的继承模式

原型式继承

function myobject(o){ 
 function F(){} 
 F.prototype = o; 
 return new F(); 
}

或者使用ES6中的Object.create()可以实现一样的效果

实际上就是创建了一个临时性的构造函数,然后将传入的对象作为这个构造函数的 原型,最后返回了这个临时类型的一个新实例。

当然这样实现的都是浅拷贝,副本对于原函数的引用类型一样是共享的。


寄生继承

寄生式(parasitic)继承是与原型式继承紧密相关的一种思路

function createAnother(original){ 
     var clone = object(original); //通过调用函数创建一个新对象
    
     clone.sayHi = function(){ //以某种方式来增强这个对象
     alert("hi"); 
     }; 
     return clone; //返回这个对象
} 

其实就是多个给构造函数加东西的过程,也没有实现函数的复用。


寄生组合继承

对于组合继承不够优秀的补充,组合继承调用了两次超类型构造函数,存在属性覆盖的情况。

基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型 原型的一个副本而已。

function inheritPrototype(subType, superType){ 
     var prototype = object(superType.prototype); //创建对象
     prototype.constructor = subType; //增强对象
     subType.prototype = prototype; //指定对象
} 

高效率体现在它只调用了一次 SuperType 构造函数,并且因此避免了在 SubType. prototype 上面创建不必要的、多余的属性。

实例

//寄生组合继承

//超构造函数
function person(name='我是默认姓名'){
    this.name=name
    this.color=['1','2','3']
}
person.prototype.getcolor=function(){

    return this.color
}

//构造函数
function people (age,name){
    //继承属性 
    person.call(this,name)

    this.age=age
}

//实现部分
people.prototype=Object.create(person.prototype)
//弥补因重写原型而失去的默认的 constructor 属性
people.prototype.constructor=people

person.prototype.addcolor=function(arr){
    
    this.color.push(...arr)
}

//实例
var fan1=new people('19','fanfan')

var fan2=new people('20','xixi')

fan1.addcolor(['add1','add2'])

console.log(fan1.getcolor());  //"1", "2", "3", "add1", "add2"
console.log(fan2.getcolor());  //"1", "2", "3"


ES6的继承

class注意点

  • class相当于es5中的构造函数
  • class定义方法时候,不能加function,方法也是定义在class的原型链上。
  • class定义的方法都是不可枚举的。
  • class只能定义方法,不用定义对象,变量
  • class默认严格模式,全局this指向undefined
  • es5中的constructor为隐式属性
class person{
    constructor(name='fanfan',age){
        this.name=name
        this.age=age
        this.color=[1.2,3]
       
    }

    getmyname(){
        //调用this依旧指向子类
        console.log(this.name);
        return this.color
    }

}

//继承
class people extends person{
    constructor(name='xixi',age){
      super(name,age)
      this.name=name
    }

    getname(){
        return super.getmyname()
    }
}

var fan1=new people('??','200')

console.log(fan1.getname()); //??  [1.2, 3]