总结
前端资料汇总
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
-
框架原理真的深入某一部分具体的代码和实现方式时,要多注意到细节,不要只能写出一个框架。
-
算法方面很薄弱的,最好多刷一刷,不然影响你的工资和成功率😯
-
在投递简历之前,最好通过各种渠道找到公司内部的人,先提前了解业务,也可以帮助后期优秀 offer 的决策。
-
要勇于说不,对于某些 offer 待遇不满意、业务不喜欢,应该相信自己,不要因为当下没有更好的 offer 而投降,一份工作短则一年长则 N 年,为了幸福生活要慎重选择!!!
喜欢这篇文章文章的小伙伴们点赞+转发支持,你们的支持是我最大的动力!
instance2.getName()
instance2.getTime()
分析一下instance的构造:
组合继承模式将类式继承和构造函数式继承相结合,可以看到构造函数式继承将父类的属性复制到子类(每次执行构造函数式继承,相当于重新new一个父类实例,所以不会有相互覆盖的可能),但是不涉及到protype,所以不会继承父类的原型方法。所以接下来马上使用类式继承,将父类的实例赋值给子类的prototype,因为子类原型prototype上继承父类的共有属性(比如books)和之前子类执行构造函数时生成的books属性同名,所以instance.books不会取原型链上的books属性,但是能够取到原型链上的父类原型pototype上的方法。
综上,组合继承完美结合了类式继承和构造函数式继承的优点,并且消除了他们的缺点。但是这种继承也不是完全没有缺点,就是执行了2遍的父类构造函数。
那有没有办法只执行1遍父类的构造函数,以减少消耗呢?
方法肯定是有的,那就是使用终结继承大法——寄生组合式继承!
原型式继承——封装类式继承
在说明终极继承大法之前,我们先学习一下它的组成之一,原型式继承。
function inheritObject(o){
// 声明一个过渡函数对象
function F(){}
// 过渡对象的原型继承父对象
F.prototype = o
// 返回过渡对象的一个实例,该实例的原型继承了父对象
return new F()
}
可以看出原型式继承和类式继承十分相似,实际上它就是类式继承的一个封装。只不过这里的子类是以过渡对象的形式出现的。
寄生式继承——原型式继承的二次封装
// 声明基对象
var book = {
name:‘js book’,
alikeBook:[‘css book’,‘html book’]
}
// 原型式继承
function inheritObject(o){
// 声明一个过渡函数对象
function F(){}
// 过渡对象的原型继承父对象
F.prototype = o
// 返回过渡对象的一个实例,该实例的原型继承了父对象
return new F()
}
// 寄生式继承
function createBook(obj){
// 通过原型式继承创建新对象
var o = new inheritObject(obj)
// 扩展新对象
o.getName = function(){
console.log(this.name)
}
return o
}
var newBook = new createBook(book)
寄生式继承其实就是对实例化后的原型继承对象进行扩展。
寄生组合式继承——终极
// 原型式继承
function inheritObject(o){
// 声明一个过渡函数对象
function F(){}
// 过渡对象的原型继承父对象
F.prototype = o
// 返回过渡对象的一个实例,该实例的原型继承了父对象
return new F()
}
// 寄生组合式继承
function inheritPrototype(subClass,superClass){
// 复制一份父类的原型副本保存在变量中
var p = inheritObject(superClass.prototype)
// 修正因为重写子类原型导致子类的constructor属性被修改
p.constructor = subClass
subClass.prototype = p
}
// 定义父类
function SuperClass(name){
this.name = name
this.colors = [‘#000000’,‘#ffffff’,‘#000fff’]
}
// 定义父类原型方法
SuperClass.prototype.getName = function(){
console.log(this.name)
}
// 定义子类
function SubClass(name,time){
// 构造函数式继承
SuperClass.call(this,name)
// 子类新增属性
this.time = time
}
// 寄生式继承父类原型
inheritPrototype(SubClass,SuperClass)
// 子类新增原型方法
SubClass.prototype.getTime = function(){
console.log(this.time)
}
// 创建2个测试方法
var instance1 = new SubClass(‘js book’,2021)
var instance2 = new SubClass(‘css book’,2022)
instance1.colors.push(‘red’)
console.log(instance1.colors)
console.log(instance2.colors)
instance2.getName()
instance2.getTime()
分析下instance1的结构:
寄生组合式继承替换掉类式继承,与构造函数式继承的结合堪称完美。首先构造函数式继承复制了父类的共有属性,然后寄生组合式继承只是将父类的原型prototype复制到了子类的prototype,并且还修正了子类constructor属性。
JavaScript不是只有一条原型链吗?怎么实现多继承呢?我们来看下下面的一段代码:
通过extend方法,我们成功将source中的属性成功复制到了target对象中,但是仅仅这样还不够,会出现几个问题:
1)如果target中有相同的属性,就会被source所覆盖
2)如果source中的某个属性是引用类型,就会导致target复制的该属性指向同一地址
3)extend方法没有涉及到prototype
解决这几个问题后,我们再考虑多继承的问题,不过是将source变成多个而已。
到这里,发现自己手写了一个深拷贝,解决了前2个问题,那prototype的问题呢?考虑到多继承和单继承不同,在此不做讨论,如果prototype也需要继承的话,可以参考extend方法。
接下来,我们需要扩展extend方法,将复制一个对象转为复制多个对象的属性。