# 继承
# 1. 原型链
问题一:当继承的原型中,包含引用类型时,公用属性将被修改 问题二:创建子类时,不能向超类型的构造函数中传参数
{
function SuperType() {
this.name = 'Super'
}
SuperType.prototype.getSuperName = function() {
return this.name
}
function SubType() {
this.subName = 'Sub'
}
SubType.prototype = new SuperType()
SubType.prototype.getSubName = function() {
return this.subName
}
// 实例化,继承之前两者所有属性
let instance = new SubType()
console.log(instance.name)
console.log(instance.getSuperName())
console.log(instance.subName)
console.log(instance.getSubName())
console.log(Object.getPrototypeOf(instance)) // SuperType 的实例 + 拓展方法
console.log(instance.constructor === SuperType) // true
boboLog.hr = '判断原型与实例的关系'
// 只要迭代中 Object.getPrototypeOf(instance) == SubType.prototype
console.log(instance instanceof SubType)
console.log(instance instanceof SuperType)
console.log(instance instanceof Object)
}
# 2. 借用构造函数
问题一:属性方法无法复用,无法继承原型中的方法。
{
function SuperType(name) {
this.name = name
this.sayName = function() {
console.log(this.name)
}
}
function SubType() {
SuperType.call(this, 'John')
this.age = 29
}
let instance = new SubType()
console.log(instance.name)
console.log(instance.age)
instance.sayName()
}
# 3. 组合继承
问题一:子元素的原型中,包含超类型构造函数的重复属性 问题二:每次设定子元素原型时,需要注意设定 constructor
{
function SuperType(name) {
this.name = name
this.colors = ['red', 'green', 'yellow']
}
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)
}
let instance1 = new SubType('john', 19)
instance1.colors.push('black')
let instance2 = new SubType('Allan', 22)
console.log(instance1.colors)
console.log(instance2.colors)
console.log(Object.getPrototypeOf(instance2).name)
console.log(Object.getPrototypeOf(instance2).colors)
}
- 原型式继承
优点一:仅仅将传入对象作为原型,用来共享属性,方便
问题一:小心引用类型 问题二:全部是 Object 构造器
{
let person = {
name: 'john',
friends: ['Hao', 'Ming']
}
let antherPerson = Object.create(person, {
name: {
value: 'Zing'
}
})
let yetPerson = Object.create(antherPerson)
console.log(antherPerson.name)
console.log(antherPerson.friends)
boboLog.hr = '原型链,继承父所有属性'
console.log(yetPerson.name)
console.log(yetPerson.friends)
}
- 寄生式继承 本质是根据传入对象,新建、拓展对象 问题:无法实现复用
function createAnother(original) {
let clone = object(original)
clone.sayHi = function() {
console.log('hi')
}
return clone
}
- 寄生组合式继承 通过构造函数来继承属性,通过原型链混成形式来继承方法。 解决组合式继承,需要第二次调用超类型构造函数问题。
{ function inheritPrototype(subType, superType) {
let 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)
}
SuperType.prototype.books = ['1', '2']
// 完成实例属性的继承
function SubType(name, age) {
SuperType.call(this, name)
this.age = age
}
inheritPrototype(SubType, SuperType)
SubType.prototype.sayAge = function() {
console.log(this.age)
}
// 测试
let instance = new SubType('Ming', 19)
console.log(SuperType.prototype)
console.log(SubType.prototype)
boboLog.hr = '查看构造函数'
console.log(SuperType.prototype.constructor)
console.log(SubType.prototype.constructor)
instance.books.push(3)
console.log(instance.books)
let instance2 = new SuperType('Wang')
console.log(instance2.books)
}
# es6
子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。
class Son extends Parent {
constructor(x, y, z) {
super(x, y)
this.z = z
}
toString() {
return this.color + ' ' + super.toString(); // 调用父类的toString()
}
}
ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。 ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。
super这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同。
第一种情况,super作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super函数。 super虽然代表了父类A的构造函数,但是返回的是子类B的实例 类似:
A.prototype.constructor.call(this)
第二种情况,super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。 ES6 规定,在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例。