javascript 多种继承方案
1. 原型链继承
- 将父类的实例赋值给子类的原型对象 --> 实现原型链继承
- 继承了 父类的实例上的属性方法 和 父类原型对象上的属性方法
- 子类实例可以沿着原型链访问 父类私有属性方法 和 父类原型对象上的属性方法
function Parent () {
this.x = '父亲'
}
Parent.prototype.getX = function () {
console.log('父方法')
}
function Child () {
this.y = '孩子'
}
Child.prototype = new Parent()
Child.prototype.constructor = Child
Child.prototype.getY = function () {
console.log('子方法')
}
let son = new Child()
console.dir(son)
console.dir(son.constructor)
console.dir(Child.prototype.constructor)
2、call 继承
- 在子类中将父类当做普通函数执行, 并将父类中的this改变成子类中的this
- 子类是实例 继承了 父类实例的属性方法 为子类实例添加私有属性方法
- 缺点:
- 只能继承父类实例的属性和方法,不能继承父类原型对象上的属性方法
- 无法实现复用,每个子类都有父类实例函数的副本,影响性能
function Parent () {
this.x = 100
}
Parent.name = '张三'
Parent.getAge = function () {
return 28
}
Parent.prototype.getX = function () { }
Parent.prototype.age = 18
function Child () {
Parent.call(this);
this.y = 200
}
var son = new Child();
let parent = new Parent()
console.dir(son);
console.dir(parent);
3、组合继承。
+ 结合 call继承 和 原型继承组成 "组合继承"
+ 继承了 父类实例上的属性方法 和 父类原型对象上的属性方法
+ 组合模式的缺点:
+ 在使用子类创建实例对象时,其原型对象中会存在两份相同的属性方法。
function Parent (name) {
this.name = name
}
Parent.prototype.sayName = function () { }
function Child (name, age) {
Parent.call(this, name)
this.age = age;
}
Child.prototype = new Parent('王五')
Child.prototype.constructor = Child;
Child.prototype.sayAge = function () { }
var son = new Child('张三', 29);
console.dir(son);
4、寄生组合式继承[推荐写法]
- 1 通过call继承 => 继承父类实例上的属性方法;
- 2 将父类的原型对象 赋值 给子类原型对象 => 实现子类继承父类原型上的属性方法
- 3 Child.prototype.constructor = Child 纠正子类constructor指向
- 优点: 原型链还能保持不变, 因此,还能够正常使用instanceof 和 isPrototypeOf()
- 这是最成熟的方法,也是现在库实现的方法
function Parent (name) {
this.name = name
}
Parent.prototype.sayName = function () { }
function Child (name, age) {
Parent.call(this, name)
this.age = age
}
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child
Child.prototype.sayAge = function () { }
let son = new Child("张三", 18)
console.dir(son)
5. 混入方式继承多个对象
- Object.assign会把 Parent2 原型上的函数拷贝到 Child 原型上,使
- Child 的所有实例都可用Parent2的方法。
function Child () {
Parent1.call(this)
Parent2.call(this)
}
Child.prototype = Object.create(Parent1.prototype)
Object.assign(Child.prototype, Parent2.prototype)
Child.prototype.constructor = Child
Child.prototype.myMethod = function () { }
6. ES6中类的继承 extends [非常类似于寄生式组合继承]
- 一旦使用 extends, 并且编写了 constructor, 必须在 constructor 函数第一行写上 super
- 从原理上类似于 call 继承; super() ===> Parent.call(this)
class Parent {
constructor (x) {
this.x = x
}
getX () { }
}
class Child extends Parent {
constructor (x) {
super(x)
this.y = 200
}
y = 200
getY () { }
}
let ch = new Child(100)
console.dir(ch);