谈谈JavaScript中继承方式

时间:2023-03-09 07:56:19
谈谈JavaScript中继承方式
聊一聊js中的继承
一、简单继承---使用原型赋值的方式继承,将实例化的对象,赋值给子级的原型
父级构造函数
function Parent(param) {
this.name = 'parent'
this.otherName = 'otherName'
this.param = param || 'param'
}
Parent.prototype.sayName = function() {
console.log('this.name :', this.name)
}
子级构造函数
function Son() {
this.name = 'son'
}
Son.prototype = new Parent() // 继承
let newSon1 = new Son()
let newSon2 = new Son() console.log('newSon1 :', newSon1) // newSon1 : Parent { name: 'son' }
// newSon1 : Parent { name: 'parent', otherName: 'otherName' } // newSon1.__proto__ 指向构造函数 Son 的原型 prototype
console.log('newSon1 :', newSon1.__proto__)
// newSon1.__proto__ 指向构造函数 Son 的原型 prototype
// Son 的 prototype 赋值为 new Parent(),所以 Son 的构造函数不是自己,而是 Parent
// newSon1.__proto__.constructor : function Parent() {
// this.name = 'parent'
// this.otherName = 'otherName'
// }
console.log('newSon1.__proto__.constructor :', newSon1.__proto__.constructor) console.log('newSon2 :', newSon2) // newSon1 : Parent { name: 'son' }
// newSon2 : Parent { name: 'parent', otherName: 'otherName' } // newSon2.__proto__ 指向构造函数 Son 的原型 prototype
console.log('newSon2 :', newSon2.__proto__) // 修改 newSon1 继承而来的 otherName 属性, newSon2也发生了变化
newSon1.__proto__.otherName = 'son1-OtherName'
console.log('newSon1.otherName :', newSon1.otherName)
console.log('newSon2.otherName :', newSon2.otherName)

缺点:

所有的实例化对象会共享属性,对于任一个属性的修改,其他的实例化对象都会同步变化
子级的构造函数也不是自己,需要重新指定
二、经典继承---改变this指向到当前的实例化对象
父级构造函数
function Parent() {
this.name = 'parent'
this.otherName = 'otherName'
}
Parent.prototype.sayName = function() {
console.log('this.name :', this.name)
}
子级构造函数
function Son(param) {
Parent.call(this, param) // 继承
}
缺点:
解决了上面提到的属性共享问题
新问题出来了,需要将方法定义在构造函数内部,否则无法被继承,
每实例化一次,构造函数里面的函数方法就创建一次,对资源是一个浪费
三、组合继承
使用call/apply方法进行属性的继承
用原型链继承的方法,继承原来的所有函数方法
父级构造函数
function Parent() {
this.name = 'parent'
this.otherName = 'otherName'
}
Parent.prototype.sayName = function() {
console.log('this.name :', this.name)
}
子级构造函数
function Son(param) {
Parent.call(this, param)
}
Son.prototype = Parent.prototype
Son.prototype.constructor = Son // 修改构造函数为自己
缺点:
因为是使用赋值引用的模式进行原型继承,
如果子级重写父级的某个属性或方法,父级也会发生改变
四、组合继承+深拷贝
父级构造函数
function Parent() {
this.name = 'parent'
this.otherName = 'otherName'
}
Parent.prototype.sayName = function() {
console.log('this.name :', this.name)
}
子级构造函数
function Son(param) {
Parent.call(this, param)
}
深拷贝原型链
deepCopy(Son.prototype, Parent.prototype)
Son.prototype.constructor
= Son // 修改构造函数为自己
function deepCopy(target, obj) {
for (const prop in obj) {
if (obj.hasOwnProperty(prop)) {
if (typeof obj[prop] === 'object') {
target[prop] = Object.prototype.toString.call(obj[prop]) === '[object Array]' ? [] : {}
deepCopy(target[prop], obj[prop])
} else {
target[prop] = obj[prop]
}
}
}
}