实现类的继承,目前常见的有四种方式:
ES6继承
借助call实现继承
借助原型链实现继承
组合式继承
一、ES6继承(非常推荐)
// ES6继承
class Parent {
constructor(name) {
this.name = name
}
say() {
console.log(this.name + ` say`);
}
play() {
console.log(this.name + ` play`);
}
}
class Child extends Parent {
constructor(name, age) {
super(name)
this.age = age
}
}
// 测试用例
let o1 = new Child('zhangsan', 18)
console.log(o1, o1.name, o1.age)
o1.say()
o1.play()
二、借助call实现继承
存在问题:子类只能继承父类的属性,不能继承父类原型上的方法
// 借助call实现继承
// 存在问题:子类只能继承父类的属性,不能继承父类原型上的方法
function Parent(name) {
this.name = name
}
Parent.prototype.say = function() {
console.log(this.name + ` say`);
}
Parent.prototype.play = function() {
console.log(this.name + ` play`);
}
function Child(name, age) {
Parent.call(this, name)
this.age = age
}
// 测试用例
let o1 = new Child('zhangsan', 18)
console.log(o1, o1.name, o1.age) // Child { name: 'zhangsan', age: 18 } zhangsan 18
// o1.say() // TypeError: o1.say is not a function
三、借助原型链实现继承
存在问题:
虽然子类可以访问父类的属性和方法,但是数据属性是所有实例共享的,修改容易造成混乱;
子类实例的构造函数是Parent
// 借助原型链实现继承
// 存在问题:数据属性共享,修改容易造成混乱;子类实例的构造函数是Parent
function Parent() {
this.name = 'parent'
this.lists = [1, 2, 3]
}
Parent.prototype.say = function() {
console.log(this.name + ` say`);
}
Parent.prototype.play = function() {
console.log(this.name + ` play`);
}
function Child(age) {
this.age = age
}
Child.prototype = new Parent()
// 测试用例
let o1 = new Child(18)
let o2 = new Child(20)
console.log(o1, o1.lists, o1.age) // Parent { age: 18 } [ 1, 2, 3 ] 18
console.log(o2, o2.lists, o2.age) // Parent { age: 20 } [ 1, 2, 3 ] 20
o2.lists.push(88)
console.log(o1, o1.lists, o1.age) // Parent { age: 18 } [ 1, 2, 3, 88 ] 18
console.log(o2, o2.lists, o2.age) // Parent { age: 20 } [ 1, 2, 3, 88 ] 20
四、组合式继承
存在问题:
父类构造函数会执行两次
子类实例的构造函数是Parent
// 组合式继承:call+原型链
// 存在问题:父类构造函数会执行两次;子类实例的构造函数是Parent
function Parent() {
this.name = 'parent'
this.lists = [1, 2, 3]
}
Parent.prototype.say = function() {
console.log(this.name + ` say`);
}
Parent.prototype.play = function() {
console.log(this.name + ` play`);
}
function Child(age) {
Parent.call(this) // 父类构造函数第二次执行
this.age = age
}
Child.prototype = new Parent() // 父类构造函数第一次执行
// 测试用例
let o1 = new Child(18)
let o2 = new Child(20)
console.log(o1, o1.lists, o1.age) // Parent { name: 'parent', lists: [ 1, 2, 3 ], age: 18 } [ 1, 2, 3 ] 18
console.log(o2, o2.lists, o2.age) // Parent { name: 'parent', lists: [ 1, 2, 3 ], age: 20 } [ 1, 2, 3 ] 20
o2.lists.push(88)
console.log(o1, o1.lists, o1.age) // Parent { name: 'parent', lists: [ 1, 2, 3 ], age: 20 } [ 1, 2, 3 ] 20
console.log(o2, o2.lists, o2.age) // Parent { name: 'parent', lists: [ 1, 2, 3, 88 ], age: 20 } [ 1, 2, 3, 88 ] 20
组合式继承优化版本:
// 组合式继承优化版本:解决了一般组合式继承存在的问题
function Parent() {
this.name = 'parent'
this.lists = [1, 2, 3]
}
Parent.prototype.say = function() {
console.log(this.name + ` say`);
}
Parent.prototype.play = function() {
console.log(this.name + ` play`);
}
function Child(age) {
Parent.call(this)
this.age = age
}
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child;
// 测试用例
let o1 = new Child(18)
let o2 = new Child(20)
console.log(o1, o1.lists, o1.age) // Child { name: 'parent', lists: [ 1, 2, 3 ], age: 18 } [ 1, 2, 3 ] 18
console.log(o2, o2.lists, o2.age) // Child { name: 'parent', lists: [ 1, 2, 3 ], age: 20 } [ 1, 2, 3 ] 20
o2.lists.push(88)
console.log(o1, o1.lists, o1.age) // Child { name: 'parent', lists: [ 1, 2, 3 ], age: 18 } [ 1, 2, 3 ] 18
console.log(o2, o2.lists, o2.age) // Child { name: 'parent', lists: [ 1, 2, 3, 88 ], age: 20 } [ 1, 2, 3, 88 ] 20