方式一:原型链继承
弊端:这种模式存在问题,子类实例共享了父类实例的属性,导致修改一个子类实例的属性值,其他子类实例的属性值也修改了。
function Parent() {
//注意类型使用引用类型
this.name = ['zhangsan']
}
Parent.prototype.getName = function () {
return this.name
}
function Child() {
}
Child.prototype = new Parent()
let child1 = new Child()
let child2 = new Child()
//测试修改子类实例,是否影响其他子类实例
child1.name[0] = 'lisi'
console.log(child1.name) // ['lisi']
console.log(child1.getName())// ['lisi']
console.log(child2.name)// ['lisi']
console.log(child2.getName())// ['lisi']
console.log(child1,child2)
方式二:构造函数继承
弊端:这种模式解决了原型链继承共享属性的问题,但是无法继承父类原型上的方法。
function Parent() {
//注意类型使用引用类型
this.name = ['zhangsan']
}
Parent.prototype.getName = function () {
return this.name
}
function Child() {
Parent.call(this)
}
let child1 = new Child()
let child2 = new Child()
//测试修改子类实例,是否影响其他子类实例
child1.name[0] = 'lisi'
console.log(child1.name) // ['lisi']
console.log(child2.name)// ['zhangsan']
console.log(child1.getName())// 报错
console.log(child2.getName())// 报错
console.log(child1,child2)
方式三:原型类和构造函数组合继承
优点:这种模式解决了原型链继承共享属性的问题,并且可以继承父类原型上的方法。
function Parent() {
console.log('父类')
//注意类型使用引用类型
this.name = ['zhangsan']
}
Parent.prototype.getName = function () {
return this.name
}
function Child() {
Parent.call(this)
}
Child.prototype = new Parent()
let child1 = new Child()
let child2 = new Child()
//测试修改子类实例,是否影响其他子类实例
child1.name[0] = 'lisi'
console.log(child1.name) // ['lisi']
console.log(child2.name)// ['zhangsan']
console.log(child1.getName())//['lisi']
console.log(child2.getName())// ['zhangsan']
console.log(child1,child2)
方式四:寄生组合继承
有组合继承的优点,还减少一次父类的调用
function Parent() {
console.log('父类')
//注意类型使用引用类型
this.name = ['zhangsan']
}
Parent.prototype.getName = function () {
return this.name
}
function Child() {
Parent.call(this)
}
//这种写法导致子类的属性和方法变动会影响父类
// Child.prototype = Parent.prototype
// Child.prototype.constructor = Child
//解决方法使用Object.create()
Child.prototype = Object.create(Parent.prototype)
let child1 = new Child()
let child2 = new Child()
//测试修改子类实例,是否影响其他子类实例
child1.name[0] = 'lisi'
console.log(child1.name) // ['lisi']
console.log(child2.name)// ['zhangsan']
console.log(child1.getName())//['lisi']
console.log(child2.getName())// ['zhangsan']
console.log(child1,child2)
//测试修改子类实例,是否影响父类实例
Child.prototype.getName1 = function () {
return this.name
}
let p = new Parent()
console.log(p)
方式五:使用Class、extends
class Parent {
constructor() {
this.name = ['zhangsan']
}
getName() {
return this.name
}
}
class Child extends Parent {
constructor() {
super()
}
}
let child1 = new Child()
let child2 = new Child()
//测试修改子类实例,是否影响其他子类实例
child1.name[0] = 'lisi'
console.log(child1.name) // ['lisi']
console.log(child2.name)// ['zhangsan']
console.log(child1.getName())//['lisi']
console.log(child2.getName())// ['zhangsan']
console.log(child1,child2)
//测试修改子类实例,是否影响父类实例
Child.prototype.getName1 = function () {
return this.name
}
let p = new Parent()
console.log(p)