前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【JS原理】代码版认干爹 - 继承

【JS原理】代码版认干爹 - 继承

作者头像
神仙朱
发布2019-08-05 14:49:30
6590
发布2019-08-05 14:49:30
举报

结束语

这是一段假的结束语

继承就是 JS 的一块大内容,反正也是说到腻的东西

继承,起码接触了看了学了研究了三年了吧

做过详细的笔记,做过Demo研究,项目中也用过很多次

但是你问我继承是什么,我还是实在没有百分百信心回答你,还是支支吾吾地

嗯...我想应该是.....母亲生了 儿子(new),母亲 是 构造函数,父亲是原型,儿子能拥有父亲所有的财产(属性和方法)

其实继承,在我看来更像是 重新认个有钱有势的爹,因为我要用你的属性和方法(我要用你的钱............)

话题远了远了 , 话锋一转......

也许这就叫 知识沉淀吧........ 好吧,我永远记得 原型是父亲..... 反正每次面试 我都是这么回答的.......

继承这个鬼东西.....可以这么称呼,我都懂,我就是说不清

继承有什么作用?

易于扩展,减少重复,易于维护

继承在我们项目中真是用得太多了,如果你完全没用到,那你就别谈面向对象了,继承就是 面向对象的一大内容。

下面主要由五种常用的继承方式,主要说缺点 和 特征代码

Person 是公共类,供其他具体的类去继承获取方法,Student 是具体类

1原型链继承

代码语言:javascript
复制
function Person(){}
function Student(){}
Student.prototype = new Person()

stu1 = new Student()

缺点有4个

构造函数的错误指向

你能看到此时打印 stu1.constructor 会 出现..... Person,很明显,你已经认错妈了,这分明不符合伦理啊,认了干爹,不能忘了妈啊

幸好,我们有办法修复你的忘恩负义

Student.prototype.constructor = Student

无法向父类传递参数

因为父类内部会增加一些属性,但是我却无法传入参数去自定义,那你说父类构造函数内部的属性,我要来干嘛??

属性污染

这里说的是 父类的构造函数会有一个 对象属性,然后大家都可以操作他,导致 共享污染

但是我想想,这是 原型链继承的问题吗???这是原型都会存在的问题!!

原型上 存放对象,都会有这个问题

因为原型链继承 涉及到 原型,所以这也是他的缺点了

属性冗余

我只想要 Person 原型的属性和方法,但是无形中,我还拿到了 Person 原型实例 person1 构造函数赋予的属性,我根本不想要,造成属性的冗余喽

2借用构造函数继承

代码语言:javascript
复制
function Person(){}
function Student(){ Person.call(this)}stu1 = new Student()

缺点

无法继承父类属性方法

可以传递参数给父类构造函数,自定义属性

3组合继承

代码语言:javascript
复制
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 原型的话,那么一样也是会污染滴,这是没有办法的事啦

4寄生组合式继承

代码语言:javascript
复制
function Person(){}
function Student(){
   Person.call(this)
}
function inheritProto(child ,parent){  
   child.prototye = Object.create(parent.prototype)
   child.prototye.constructor = child
}

这就是最优的继承方式了

  1. 基于组合继承
  2. 不用重复调用父类构造函数,只需要继承原型
  3. 优化了 组合继承的 【通过new挂载原型会产生的多余属性】

大家有的人可能不知道- 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 拿不到了??"

比如这样

代码语言:javascript
复制
// copyObj 比如是深度赋值对象的方法
Studetn.prototype=copyObj(Person.prototype)
// 后面给 Person 原型新添加的方法
Person.prototype.newFn = function(){} 

很明显啦,child 不会继承到这部分新家产,这个想法,

MMP哦,老师果然没有骗我,真绝壁是最优的继承方法了

然后一切结束在 ES6 出现之后

5ES6 Class 继承

代码语言:javascript
复制
class Person{    
    constructor(arg1){ this.arg1 =arg1 }
   getArg1(){}
}
class Student extends Person{    
    constructor(arg1,arg2){
       super(arg1) // 调用 Person 构造函数
       this.arg2= arg2
   }    
   getArg2(){}
}

又方便,又好写,又好看,清晰易懂,路转粉

别看 ES6 除了这么多年,会写 class 还是挺有逼格的

结束语

这是一段真的结束语

欢乐的时光,总是过得特别快,但是我就是用了一天

我衷心在以后的面试中,别人问继承的时候

可以从容不迫地告诉他,幼稚问题,下一个

面试官:好的,本次面试结束,下一个

啊,我说的是,下一个问题啊喂....

好吧,匆忙结束,写了一篇文章,又花了一天..........

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-12-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 神仙朱 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1原型链继承
  • 2借用构造函数继承
  • 3组合继承
  • 4寄生组合式继承
  • 5ES6 Class 继承
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档