1、原型链继承
function SuperType(type) {
this.property = true
this.colors = ['red', 'blue']
this.type = type
}
SuperType.prototype.getSuperValue = function() {
console.log(this.property)
}
function SubType(type) {
this.subproperty = false
this.subtype = type
}
// 如果这里是 SubType.prototype = SuperType.prototype
// 则 this.property 值为 undefined
SubType.prototype = new SuperType('super')
SubType.prototype.getSubValue = function() {
console.log(this.subproperty)
}
const instance = new SubType('one')
instance.getSuperValue()
instance.getSubValue()
console.log(instance instanceof SubType, instance.constructor)
console.log(instance instanceof SuperType)
instance.colors.push('black')
console.log(instance.colors, instance.type, instance.subtype)
const instance2 = new SubType('two')
console.log(instance2.colors, instance2.type, instance2.subtype)
// 所有实例的 colors 属性指向同一个对象,一改全改
// 如果父类有参数,没法带进去
2、构造函数继承
function SuperType(type) {
this.property = true
this.colors = ['red', 'blue']
this.type = type
}
SuperType.prototype.getSuperValue = function() {
console.log(this.property)
}
function SubType(type) {
SuperType.call(this, type)
// 为了确保不被父级的属性覆盖,可以在这之后再赋值子类的属性
this.subproperty = true
}
const instance1 = new SubType('one')
console.log(instance1 instanceof SubType, instance1.constructor)
console.log(instance1 instanceof SuperType, instance1.type)
// 没有用到原型的方法属性
// instance1.getSuperValue()
instance1.colors.push('black')
console.log(instance1.colors)
const instance2 = new SubType('two')
console.log(instance2.colors, instance2.type)
3、组合继承(原型链继承 + 构造函数继承)
function SuperType(type) {
this.property = 'true111'
this.colors = ['red', 'blue']
this.type = type
}
SuperType.prototype.getSuperValue = function() {
console.log(this.property)
}
function SubType(type) {
SuperType.call(this, type) // 调用一次
// 为了确保不被父级的属性覆盖,可以在这之后再赋值子类的属性
this.subproperty = true
}
SubType.prototype = new SuperType() // 调用两次
// 如果没有这一步,最终顺着父类的原型链指向父类SuperType
SubType.prototype.constructor = SubType
const instance1 = new SubType('one')
console.log(instance1 instanceof SubType, instance1.constructor)
console.log(instance1 instanceof SuperType, instance1.type)
instance1.getSuperValue()
instance1.colors.push('black')
console.log(instance1.colors)
const instance2 = new SubType('two')
console.log(instance2.colors, instance2.type)
4、原型式继承
// 缺点:引用类型属性依然是共享的
function object(o) {
function F(){}
F.prototype = o
return new F()
}
const person = {
name: 'xiaoming',
colors: ['1', '2']
}
const p1 = object(person)
const p2 = object(person)
console.log(p1.colors, p2.colors)
p2.colors.push('3')
console.log(p1.colors, p2.colors)
// 等同于
const p3 = Object.create(person, {
name1: {
value: 'xiaohong'
}
})
console.log(p1, p2, p3, p3.name)
5、寄生式继承
function object(o) {
function F(){}
F.prototype = o
return new F()
}
// 包了一层,定义了个方法增强对象,
// 缺点是函数没法复用,引用类型属性依然是共享的
function createObject(o) {
const clone = object(o)
clone.say = function() {
console.log(this.colors)
}
return clone
}
const person = {
name: 'xiaoming',
colors: ['1', '2']
}
const p1 = createObject(person)
const p2 = createObject(person)
console.log(p1.colors, p2.colors)
p2.colors.push('3')
console.log(p1.colors, p2.colors)
p2.say()
6、寄生式组合继承
function SuperType(type) {
this.name = 'true111'
this.colors = ['red', 'blue']
}
SuperType.prototype.getSuperValue = function() {
console.log(this.colors)
}
function SubType(name, age) {
SuperType.call(this, name) // 调用一次
// 为了确保不被父级的属性覆盖,可以在这之后再赋值子类的属性
this.age = age
}
SubType.prototype = new SuperType() // 调用两次
// 如果没有这一步,最终顺着父类的原型链指向父类SuperType
SubType.prototype.constructor = SubType
const s1 = new SubType('saaa', 18)
const s2 = new SubType('sbbb', 19)
console.log('~1~', s1, s2)
s2.colors.push('yellow')
console.log('~2~', s1, s2)
// 这样每个 SubType 实例都有两组 name 和 colors,
// 一组是自身属性下,一组是原型链指向父类实例的
function inherit(newType, superType) {
newType.prototype = Object.create(superType.prototype)
newType.prototype.constructor = newType
}
function NewType(name, age) {
SuperType.call(this, name) // 调用一次
// 为了确保不被父级的属性覆盖,可以在这之后再赋值子类的属性
this.age = age
}
inherit(NewType, SuperType)
const n1 = new NewType('nbbb', 20)
const n2 = new NewType('nccc', 21)
console.log('~3~', n1, n2, n1.constructor)
n1.colors.push('yellow')
console.log('~4~', n1, n2)
7、ES6 Class 继承(略)
总结
  寄生式组合继承是 ES5 最完善的继承方式。细细一看,不就是跟 new 一个实例所做的操作差不多吗。不同之处在于复制的对象原型不一样。当然具体还是有差别,一个是原型,一个实例化。