JS继承的6种方式

144 阅读3分钟
  1. 原型链继承

function SuperType() {
    this.property = true
}
SuperType.prototype.getSuperVal = function() {
    return this.property
}

function SubType() {
    this.subproperty = false
}

SubType.prototype = new SuperType()
SubType.prototype.getSubVal = function() {
    return this.subproperty
}
SubType.prototype.getSuperVal = function() {
    return false
}
let instance = new SubType()
console.log(instance.getSuperVal())


//原型链继承的问题
//1、包含引用类型值的原型会被所有实例共享
//2、创建的子类型的实例时,不能向超类型的构造函数中传递参数
function SuperType() {
    this.color = ['red', 'blue', 'yellow']
}
function SubType() {

}
SubType.prototype = new SuperType()
let instance1 = new SubType()
instance1.color.push('pink')

let instance2 = new SubType()
console.log(instance2.color) //["red", "blue", "yellow", "pink"]
  1. 构造函数继承

//优点:可以在子类型构造函数中向超类型构造函数传递参数
//缺点:在超类型的原型中定义的方法,对子类型而言不可见,无法实现函数复用
function SuperType(name) {
    this.name = name
    this.color = ['red', 'blue', 'yellow']
    console.log(name)
    this.fn = function(){
        console.log('fn is call')
    }
}

function SubType() {
    SuperType.call(this, 'nick')
}

var instance3 = new SubType()
instance3.color.push('black')
console.log(instance3.color)
var instance4 = new SubType()
console.log(instance4.color)
  1. 组合继承

//组合继承是将原型链及借用构造函数的技术组合到一起
//其原理是:使用原型链实现对原型属性和方法的继承,再通过借用构造函数实现对实例属性的继承
//优点:js中最常用的继承模式,instanceof 和 isPrototypeOf()能够识别组合继承创建的对象
//缺点:无论什么情况下,都会调用两次超类型构造函数
function SuperType(name) {
    this.name = name
    this.color = ['red', 'blue']
}
SuperType.prototype.sayName = function() {
    console.log('supertype->', this.name)
    return 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('subtype->', this.age)
    return this.age
}

var instance5 = new SubType('john', 30)
instance5.color.push('green')
console.log(instance5, instance5.sayName(), instance5.sayAge())

var instance6 = new SubType('mary', 26)
instance6.color.push('orange')
console.log(instance6, instance6.sayName(), instance6.sayAge())
  1. 原型式继承

//借助原型基于已有对象创建新对象,本质上object对传入的对象执行了一次浅复制
//ECMAScript5 通过新增Object.create()方法规范化了原型式继承,第一个参数传入原型对象,第二个参数传入自定义描述
function object(o) {
    function F() {} //创建一个临时的构造函数
    F.prototype = o //将传入的对象作为这个函数的原型
    return new F() //返回这个临时类型的新实例
}

var person = {
    name: 'dalin',
    friends: ['kiol', 'mary']
}
var person1 = object(person)
person1.name = 'jekon'
person1.friends.push('tina')

var person2 = object(person)
person2.name = 'erika'
person2.friends.push('luna')

console.log(person, person1, person2)
  1. 寄生式继承

//使用原型式继承,创建工厂方法内部增强对象并返回
//缺点:使用寄生式继承为对象添加函数, 会由于不能做到函数复用而降低效率,这点和构造函数模式类似
function createAnother(original) {
    var clone = Object.create(original) //创建新对象
    clone.sayHi = function() { //某种方式增强对象
        console.log('hi')
    }
    return clone //返回这个对象
}

var personAnother = {
    name: 'yelia',
    friends: ['bill', 'verlia']
}
var personObj = createAnother(personAnother)
personObj.sayHi()
  1. 寄生组合式继承

//使用组合式继承(借用构造函数继承属性,原型链方式继承方法)方式,把原来子类型原型调用超类型构造函数的方式
//换为继承超类型原型的副本(寄生式继承方式),再将结果指定给子类型原型
function inheritPrototype(subType, superType) {
    var prototype = Object.create(superType.prototype) //创建对象
    prototype.constructor = subType //增强对象
    subType.prototype = prototype //指定对象
}

function SuperType(name) {
    this.name = name
    this.colors = ['red', 'blue']
}
SuperType.prototype.sayName = function() {
    console.log(this.name)
    return this.name
}

function SubType(name, age) {
    SuperType.call(this, name)
    this.age = age
}

inheritPrototype(SubType, SuperType)

SubType.prototype.sayAge = function() {
    console.log(this.age)
    return this.age
}
var instance7 = new SubType('lily', 28)
console.log(instance7, instance7.sayName(), instance7.sayAge())