基于对象的原型链来实现,在 ECMAScript 中描述了原型链的概念,并将原型链作为实现继承的主要方法。可以总结为:当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有自己的原型,于是就这样一直找下去,也就是原型链的概念。原型链的尽头一般来说都是 Object.prototype
function Parent() {
this.name = 'Parent'
}
Parent.prototype.getName = function () {
return this.name
}
function Child() {}
Child.prototype = new Parent() // 继承自Parent
Child.prototype.constructor = Child
const child = new Child()
console.log(child.getName()) // "Parent"
缺点:
基于以上问题,在实践中很少会单独使用原型链。
构造函数继承的思想主要是在子类构造函数中调用父类构造函数,使用 call 或 apply 实现
function Parent(name) {
this.name = name
}
function Child(name, age) {
Parent.call(this, name) // 继承自Parent
this.age = age
}
const child = new Child('Child', 10)
console.log(child.name) // "Child"
console.log(child.age) // 10
优点:
缺点:
基于以上问题,构造函数继承的技术也是很少单独使用的。
结合了原型链继承和构造函数继承的优点,既可以继承实例属性,也可以继承原型属性
function Parent(name) {
this.name = name
}
Parent.prototype.getName = function () {
return this.name
}
function Child(name, age) {
Parent.call(this, name) // 继承实例属性
this.age = age
}
Child.prototype = new Parent() // 继承原型属性
Child.prototype.constructor = Child
const child = new Child('Child', 10)
console.log(child.getName()) // "Child"
console.log(child.age) // 10
优点:
缺点:
寄生式继承的思路是,创建一个仅用于封装继承过程的函数,该函数在内部以某种方式增强对象,最后返回这个对象。如下面的例子所示
function Parent(name) {
this.name = name
}
Parent.prototype.getName = function () {
return this.name
}
function Child(name, age) {
Parent.call(this, name) // 继承实例属性
this.age = age
}
Child.prototype = Object.create(Parent.prototype) // 继承原型属性
Child.prototype.constructor = Child
const child = new Child('Child', 10)
console.log(child.getName()) // "Child"
console.log(child.age) // 10
优点:
缺点:
ES6 引入了 class 关键字,提供了更直观的语法糖来实现继承
class Parent {
constructor(name) {
this.name = name
}
getName() {
return this.name
}
}
class Child extends Parent {
constructor(name, age) {
super(name) // 继承实例属性
this.age = age
}
}
const child = new Child('Child', 10)
console.log(child.getName()) // "Child"
console.log(child.age) // 10
优点:
优点: