实现继承的九种方式

153 阅读3分钟

原型链继承
原理:将父类的实例指向子类的原型
缺点:牵一发而动全身,因为共享同一个原型,所以父类原型的修改会直接影响子类,且任一子类的修改也会影响其他子类

function Parent(name){
    this.name = name
}
Parent.prototype.age = '55'
function Son(){
    this.name = "Mike"
}
Son.prototype = new Parent()
var son = new Son()
console.log(son.age)    // 55
console.log(son instanceof Parent)   // true

构造函数继承
原理:复制父类的实例给子类
缺点:不能实现函数复用

function Parent(name){
    this.name = name
}
Parent.prototype.age = '55'
function Son(){
    Parent.call(this, 'son')
    this.age = '27'
}
var son = new Son()
console.log(son.name)  // son
console.log(son.age)   // 27
console.log(son instanceof Parent)  // false

组合式继承
原理:原型链继承+构造函数继承
缺点:需要调用两次父类,子级的调用覆盖了原型调用

function Parent(name){
    this.name = name
    console.log("调用父级")  // 调用父级 * 2
}
Parent.prototype.age = '55'
function Son(name){
    Parent.call(this, name)
    this.age = '27'
}
Son.prototype = new Parent()
var son = new Son('Alice')
console.log(son.name)  // Alice
console.log(son.age)   // 27
console.log(son instanceof Parent)  // true

实例继承
原理:给父类的实例添加属性和方法,作为子类返回

function Parent(name){
    this.name = name
}
function Son(args){
    var instance = new Parent(args)
    instance.age = '27'
    instance.sleep = function(){
        console.log('sleep')
    }
    return instance
}
var son = new Son('Tom')
console.log(son.name)  // Tom
console.log(son.age)   // 27
console.log(son instanceof Parent)  // true

原型式继承
ES5 通过新增 Object.create()方法规范化了原型式继承,此方法可以接受两个参数,第一个参数最为新对象原型的对象 和一个为新对象定义额外属性的对象.
原理:借助原型基于已有的对象创建新的对象
缺点:和原型链继承相似,牵一发而动全身

function object( O ){	    // 传递一个字面量函数
    function F(){}	    // 创建一个构造函数
    F.prototype = O         // 将字面量函数赋值给构造函数的原型
    return new F()	    // 返回构造函数的实例
 }

寄生式继承
原理:(基于原型式继承+工厂模式)创建一个用于封装继承过程的函数,在函数通过某种方式增强这个对象,最后将这个对象返回
缺点:原型继承存在的缺点他都存在
使用寄生式继承为对象添加方法,会由于不能做到方法的复用而降低效率,这一点和构造函数模式类似

function object(o){
    function F(){}
    F.prototype = o
    return new F()
}
function createAnother(original){
    var clone = object(original)  // 调用函数创建一个新的对象
    clone.fn = function(){} 	// 增强这个对象
    return clone	// 返回这个对象
}

寄生组合式继承
原理:构造函数继承+创建子类和父类的链接

function SuperType(name){
    this.name = name
    this.colors = ['red','green','yellow']
}
SuperType.prototype.sleep = function(){ alert('prototype') }
function SubType(name,age){
    SuperType.call(this,name)
    this.age = age
}
function inherit(SubType,SuperType){
    var proto = SuperType.prototype
    proto.constructor = SubType
    SubType.prototype = proto
}
inherit(SubType,SuperType)

圣杯模式

let inherit = (function(){
function F(){} //函数是一个闭包,仅用做一个缓冲而不做他用
    return function(son,parent){
    F.prototype = parent.prototype
    // son.prototype = F.prototype; /* 不能这么写,因为这样写就相当于对象son、parent和 F 共享原型了 */
    son.prototype = new F() 
    // 使对象targetSon试图修改自身属性时仅仅是以buffer函数作为对象进行修改,而不会影响到其他对象
    son.prototype.uber = parent.prototype 
    son.prototype.constructor = son 
    }
})()

ES6 class继承

注:一定要有super,否则新建实例时会报错。因为子类没有自己的this对象,需要继承父类的this对象,如果没有super子类就得不到父类的this对象
class Parent{
    constructor(props){
        this.name = props.name || 'Unknown'
    }
    eat(){
        console.log(this.name + '会来吃东西')
    }
}
class Son extends Parent{
    constructor(props,myAttribute){
        super(props)
        this.type = props.type
        this.attr = myAtrribute
    }
    play(){  
        console.log('子类的私有方法')  
    }
    myattr(){
        console.log('子类的自由方法二')
    }
}