结束语
这是一段假的结束语
继承就是 JS 的一块大内容,反正也是说到腻的东西
继承,起码接触了看了学了研究了三年了吧
做过详细的笔记,做过Demo研究,项目中也用过很多次
但是你问我继承是什么,我还是实在没有百分百信心回答你,还是支支吾吾地
嗯...我想应该是.....母亲生了 儿子(new),母亲 是 构造函数,父亲是原型,儿子能拥有父亲所有的财产(属性和方法)
其实继承,在我看来更像是 重新认个有钱有势的爹,因为我要用你的属性和方法(我要用你的钱............)
话题远了远了 , 话锋一转......
也许这就叫 知识沉淀吧........ 好吧,我永远记得 原型是父亲..... 反正每次面试 我都是这么回答的.......
继承这个鬼东西.....可以这么称呼,我都懂,我就是说不清
继承有什么作用?
易于扩展,减少重复,易于维护
继承在我们项目中真是用得太多了,如果你完全没用到,那你就别谈面向对象了,继承就是 面向对象的一大内容。
下面主要由五种常用的继承方式,主要说缺点 和 特征代码
Person 是公共类,供其他具体的类去继承获取方法,Student 是具体类
function Person(){}
function Student(){}
Student.prototype = new Person()
stu1 = new Student()
缺点有4个
构造函数的错误指向
你能看到此时打印 stu1.constructor 会 出现..... Person,很明显,你已经认错妈了,这分明不符合伦理啊,认了干爹,不能忘了妈啊
幸好,我们有办法修复你的忘恩负义
Student.prototype.constructor = Student
无法向父类传递参数
因为父类内部会增加一些属性,但是我却无法传入参数去自定义,那你说父类构造函数内部的属性,我要来干嘛??
属性污染
这里说的是 父类的构造函数会有一个 对象属性,然后大家都可以操作他,导致 共享污染
但是我想想,这是 原型链继承的问题吗???这是原型都会存在的问题!!
原型上 存放对象,都会有这个问题
因为原型链继承 涉及到 原型,所以这也是他的缺点了
属性冗余
我只想要 Person 原型的属性和方法,但是无形中,我还拿到了 Person 原型实例 person1 构造函数赋予的属性,我根本不想要,造成属性的冗余喽
function Person(){}
function Student(){ Person.call(this)}stu1 = new Student()
缺点
无法继承父类属性方法
可以传递参数给父类构造函数,自定义属性
function Person(){}
function Student(){ Person.call(this)}Student.prototype = new Person()
stu1 = new Student()
缺点
调用父类两次
Person .call( this ) 调用一次,new Person() 调用一次
属性冗余
比如 Person 构造函数中 会 给实例一个属性 name
此方法 继承 Person 之后,Person 实例 本身有一个name,Person 原型又有一个 name,Person 原型的 name 根本不是我想要的
造成冗余喽,占用对象堆内存喽
是否解决引用类型属性共享污染的问题??
比如 Person 构造函数内部会 分配一个 this.friends=[]
这里也是使用了 new Person 绑定的原型,那么同样会有 原型链的 引用类型属性共享污染问题啦
但是!因为借用了造函数,虽然原型上一样会有 friends,但是每个实例也都会分配有一个独立的 friends
所以当大家访问 stu.friends 的时候,并不会操作到 Person 原型上的 friends
应该算是缓解了共享污染的问题
但是如果你还是要 操作 Person 原型的话,那么一样也是会污染滴,这是没有办法的事啦
function Person(){}
function Student(){
Person.call(this)
}
function inheritProto(child ,parent){
child.prototye = Object.create(parent.prototype)
child.prototye.constructor = child
}
这就是最优的继承方式了
大家有的人可能不知道- Object.create(Person.prototype) 会怎么样 其实我一开始也不知道,其实 Object.create 传入 一个对象 a,会返回一个对象 b 你可以看到 对象a 成了 对象 b 的原型 所以 Object.create 可以说成是 为 新对象指向原型的一个方法
那我们现在 寄生组合,child 要访问到 parent 的 方法,其实是经过了两个原型
student.__proto__.__proto__
而后我有个想法,为什么要增加访问深度,这样不是会更慢吗?我可不可以这样
Student.prototype=Person.prototype
哎呀,我去,可以呀,这样不是完美了??直接赋值引用,减少层级深度,
不对! 如果我要给 Student.prototype 添加只属于 Student 的方法
Student.prototype.getName
啊,那不是也添加到了 parent.prototype.getName 中,那岂不是污染了,不行不行
于是我又有了另一个想法
Student.prototype=copyObj(Person.prototype)
这样,我不就不会影响到 Person 的原型了吗 哈哈哈哈哈
就在我沾沾自喜时,
"如果我后面要给 Person原型添加新属性新方法,那岂不是 student 拿不到了??"
比如这样
// copyObj 比如是深度赋值对象的方法
Studetn.prototype=copyObj(Person.prototype)
// 后面给 Person 原型新添加的方法
Person.prototype.newFn = function(){}
很明显啦,child 不会继承到这部分新家产,这个想法,
MMP哦,老师果然没有骗我,真绝壁是最优的继承方法了
然后一切结束在 ES6 出现之后
class Person{
constructor(arg1){ this.arg1 =arg1 }
getArg1(){}
}
class Student extends Person{
constructor(arg1,arg2){
super(arg1) // 调用 Person 构造函数
this.arg2= arg2
}
getArg2(){}
}
又方便,又好写,又好看,清晰易懂,路转粉
别看 ES6 除了这么多年,会写 class 还是挺有逼格的
结束语
这是一段真的结束语
欢乐的时光,总是过得特别快,但是我就是用了一天
我衷心在以后的面试中,别人问继承的时候
可以从容不迫地告诉他,幼稚问题,下一个
面试官:好的,本次面试结束,下一个
啊,我说的是,下一个问题啊喂....
好吧,匆忙结束,写了一篇文章,又花了一天..........