这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战
前言
想必,点进来的都是随时可以继承家产,上班只是为了享受生活,随时能回去躺平的大佬。好,收回正题,毕竟还要靠代码维持生计。
继承是面向对象编程中讨论最多的话题,但却是日常业务开发中极易被忽略的一块内容。
本文围绕《Javascript高级程序设计第4版》
和面试高频问题
进行知识点梳理。
原型链继承
基本思想: 函数Child
没有使用默认显式原型,而是替换成函数Parent
的实例。使Parent
的实例可访问的属性和方法同样存在在函数Child
实例的原型链上,从而实现了继承。
function Parent() {
this.isRich = true
}
Parent.prototype.getIsRich = function() {
console.log('能回去继承家产么?', this.isRich)
}
function Child() {
}
Child.prototype = new Parent()
let child1 = new Child('')
console.log(child1.getIsRich()) // 能回去继承家产么? true
Child
函数成功继承了函数Parent
的属性,child1
可以实现继承家产,不用在外打工。
问题:原型上引用类型被所有实例共享。
function Parent() {
this.banCreditCard = []
this.isRich = true
}
Parent.prototype.getBanCreditCard = function() {
console.log(this.banCreditCard)
}
function Child() {}
Child.prototype = new Parent()
let child1 = new Child()
let child2 = new Child()
child1.banCreditCard.push('建设银行')
child2.getBanCreditCard() // 建设银行
child1
与child2
共同拥有parent
一起给与的消费信用卡,但当child1
建设银行信用卡消费超限额了,导致child2
也不能使用该信用卡继续消费。
构造函数继承
基本思想:Child
函数执行Parent
函数,将当前函数执行上下文this
指向child
实例。
function Parent(name) {
this.name = name
this.isRich = true
this.banCreditCard = []
this.getBanCreditCard = function() {
console.log(this.banCreditCard)
}
}
Parent.prototype.getIsRich = function() {
console.log('能回去继承家产么?', this.isRich)
}
function Child(name) {
Parent.call(this, name)
}
let child1 = new Child('瑾行')
let child2 = new Child('七金')
child1.banCreditCard.push('建设银行')
child2.getBanCreditCard() // []
child1.getRich() // child1.getRich is not a function
child2.getRich() // child2.getRich is not a function
parent
为了减少家庭内部矛盾?,单独给child1
与child2
创办信用卡,这就不会造成child1
信用卡限额导致child2
不能继续消费的问题。解决了原型链继承引用类型共享的问题,且可传参。
问题:每创建一个实例都会创建一遍方法,且Parent
原型链上的方法无法继承。相当于每个child
都得去记住自己信用卡的联系方式去确认信用卡是否停用,很麻烦。
组合继承
基本思想:方法使用原型链继承
,属性使用构造函数继承
。
function Parent(name) {
this.name = name
this.isRich = true
this.banCreditCard = []
}
Parent.prototype.getBanCreditCard = function() {
console.log(this.banCreditCard)
}
Parent.prototype.getRich = function() {
console.log('能回去继承家产么?', this.isRich)
}
Child.prototype = new Parent()
Child.prototype.constructor = Child
function Child(name) {
Parent.call(this, name)
}
let child1 = new Child('瑾行')
let child2 = new Child('七金')
child1.banCreditCard.push('建设银行')
child2.getBanCreditCard() // []
child1.getRich() // 能回去继承家产么? true
child2.getRich() // 能回去继承家产么? true
解决了引用属性共享问题,且避免方法被重复创建的问题。相当于child1
与child2
能各自使用自己信用卡的同时,又能使用同样的方法(手机号)去联系确认信用卡是否停用。
问题:基本问题解决了,但不难发现,我们会调用两次Parent
构造函数,就是创建Child
的原型的时候和创建实例的时候,还有待优化。
原型式继承
基本思想:使用Object.create
的对parent
参数对象浅复制,达到继承parent
中的属性和方法。
Object.create
的原生实现,将传入的对象作为创建对象的隐式原型。
function objectCreate(o) {
function F(){}
F.prototype = o
return new F()
}
原型式继承思想代码基本实现如下。
let parent = {
name: '爸爸',
isRich: true,
banCreditCard: []
}
let child1 = Object.create(parent)
let child2 = Object.create(parent)
child1.name = '瑾行'
child2.name = '七金'
child2.banCreditCard.push('建设银行')
console.log(child1.name) // 瑾行
console.log(child2.name) // 七金
console.log(child1.banCreditCard) // ['建设银行']
问题:引用属性会被实例共享,无法传递参数,具备与原型链继承一样的问题。
寄生式继承
基本思想:在原型式继承上增强浅复制能力,创建一个用于继承方法的函数。
function objectCreateEnhance(o) {
let clone = Object.create(o)
clone.say = function() {
console.log('hello world')
}
return clone
}
问题:没有解决引用属性的问题,函数也同样需要重复创建。
寄生组合式继承
基本思想: 在组合继承的基础上进一步优化,将Parent
显示原型浅复制赋值给Child
显示原型,解决组合继承创建原型多调用Parent
构造函数的问题。
function Parent(name) {
this.name = name
this.isRich = true
this.banCreditCard = []
}
Parent.prototype.getBanCreditCard = function() {
console.log(this.banCreditCard)
}
Parent.prototype.getRich = function() {
console.log('能回去继承家产么?', this.isRich)
}
// 重点思想
function inheritPrototype(child,parent) {
let prototype = Object.create(parent.prototype)
child.prototype = prototype
prototype.constructor = child
}
inheritPrototype(Child, Parent)
function Child(name) {
Parent.call(this, name)
}
let child1 = new Child('瑾行')
let child2 = new Child('七金')
child1.banCreditCard.push('建设银行')
child2.getBanCreditCard() // []
child1.getRich() // 能回去继承家产么? true
child2.getRich() // 能回去继承家产么? true
寄生组合式继承是目前最完美的继承方案:只调用一次Parent
的构造函数,避免在Parent.prototype
上添加多余的属性和方法,原型链保持不变。可以让child1
和child2
合理共同继承家产的同时,避免太多繁杂的事情,人生巅峰!!!
extends
ES6新增的extends核心思想和寄生组合继承类似。相当于寄生组合继承的语法糖。
经过babel
转义如下:
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
// subClass.prototype = superClass.prototype
// subClass.prototype.constructor = subClass
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
// subClass.__proto__ = superClass
if (superClass) {
Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}
}
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!