JS类继承常用方式发展史

涉及知识点

前言

当JS被创造出来的时候,并没有使用当时最流行的类方式,像(JAVA C++)。具体原因为:

对于有基于类的语言经验的开发人员来说,JavaScript 有点令人困惑 (如Java或C ++) ,因为它是动态的,并且本身不提供一个类实现。(在ES2015/ES6中引入了class关键字,但只是语法糖,JavaScript 仍然是基于原型的)。

参考2

1 构造函数方式继承

1.1 通过构造函数多步骤完成继承单个对象

  1. /**
  2. * log-console.log的简单封装插件
  3. *
  4. * @demo log(xxx) ==> console.log(xxx)
  5. * @explain 1 可以代替console.log()使用
  6. * @explain 2 可以运行在浏览器环境和NodeJs环境
  7. */
  8. function log() {
  9. console.log.apply(console, arguments);
  10. }
  11. /**
  12. * Student--学生抽象类-希望作为其中的一个父类
  13. * @param {String} guide 职业
  14. */
  15. function Student({guide}) {
  16. this.guide = guide;
  17. }
  18. Student.prototype.showGuide = function() {
  19. log(this.guide);
  20. }
  21. /**
  22. * People--子类,希望能够继承Student
  23. *
  24. * @want People的实例对象拥有Student的特性,且可以自己扩展
  25. * 扩展后不影响Student
  26. */
  27. function People(props) {
  28. Student.call(this, props);
  29. this.country = props.country;
  30. }
  31. /**
  32. * 通过中间对象(函数)来实现People正确的原型链指向
  33. *
  34. * @explain step1 MidFn 创建一个空函数
  35. * @explain step2 把MidFn函数的原型指向Student.prototype
  36. * @explain step3 把People原型对象指向MidFnde原型对象, MidFn的原型正好指向Student.prototype
  37. * @explain step4 把People原型的构造函数修复为People
  38. * @explain step5 People扩展方法测试是否会影响Student
  39. */
  40. // step1
  41. function MidFn() {}
  42. // step2
  43. MidFn.prototype = Student.prototype;
  44. // step3
  45. People.prototype = new MidFn();
  46. // step4
  47. People.prototype.construtor = People;
  48. // step5
  49. People.prototype.showCountry = function() {
  50. log(this.country);
  51. }
  52. const jeson = new People({
  53. guide: 'web前端',
  54. country: '中国'
  55. });
  56. jeson.showGuide();
  57. jeson.showCountry();
  58. log(jeson instanceof People); // => true
  59. log(jeson instanceof Student); // => true
  60. const student1 = new Student({
  61. guide: '全栈',
  62. country: 'Chinese'
  63. });
  64. student1.showGuide(); // => '全栈'
  65. student1.showCountry(); // => 出错

分析 back

  • 1 通过创建一个中间对象函数,想办法将原型链修改为:

    new People() ----> People.prototype ----> Student.prototype ----> Object.prototype ----> null

    参考1
  • 2 为什么不只使用People.prototype = Student.prototype方式?
    • 答:这个方法简单粗暴也是可以使用的,为什么不使用呢?1 耦合性太高了,修改其中的一个类,另一个也会受影响,而且如果不知道Student.showGuide方法存在,子类写了这个方法,那么恭喜,Student.prototype.showGuide方法会被子类的People.prototype.showGuide替换掉,2 为了解耦(追求更好的方式--提高编程水平)
  • 3 子类的构造函数里面 父类.call(this, param1, param2)是为了实例化子类的时候将参数传给父类

1.2 封装多步骤完成继承单个对象

  1. /**
  2. * inherits 封装继承的动作到inherits函数,简化代码,美化世界
  3. * @explain 通过封装4步骤完成继承
  4. */
  5. function inherits(Child, Parent) {
  6. const MidFn = function() {}
  7. MidFn.prototype = Parent.prototype;
  8. Child.prototype = new MidFn();
  9. Child.prototype.construtor = Child;
  10. }
  11. /**
  12. * 执行继承函数实现原型继承链
  13. */
  14. inherits(People, Student);

分析 back

  • 1 封装继承的多步骤为一个inherits函数,简化代码参考1

1.3 Object.create()方式完成继承单个对象

  1. /**
  2. * inherits 封装继承的动作到inherits函数,简化代码,美化世界
  3. * @explain 通过Object.create实现继承
  4. */
  5. function inherits(Child, Parent) {
  6. Child.prototype = Object.create(Parent.prototype);
  7. Child.prototype.constructor = Child;
  8. }
  9. /**
  10. * 执行继承函数实现原型继承链
  11. */
  12. inherits(People, Student);

分析 back

  • 1 通过ES5提供的Object.create()完成继承
  • 2 由于new后生成的实例对象是对象(键值对),实例对象通过其构造函数的原型对象继承属性。而Object.create()可以完成对象的扩展参考3

2 继承多个对象

2.1 Object.create() Object.assign() 遍历复制实现多个对象继承

  1. /**
  2. * Student--学生类,作为People的一个父类
  3. * @class
  4. * @param {*} guide 职业
  5. */
  6. function Student(props) {
  7. this.guide = props.guide;
  8. this.class = props.class;
  9. }
  10. Student.prototype.showGuide = function() {
  11. log(this.guide);
  12. }
  13. /**
  14. * Sex--性别类,作为People的一个父类
  15. * @class
  16. * @param {*} sex 性别
  17. */
  18. function Sex({sex}) {
  19. this.sex = sex;
  20. }
  21. Sex.prototype.showSex = function() {
  22. log(this.sex);
  23. }
  24. /**
  25. * People--人类--子类(想继承Student和Sex)
  26. *
  27. * @want People的实例对象拥有Student Sex的特性,且可以自己扩展
  28. * 扩展后不影响Student和Sex
  29. */
  30. function People(props) {
  31. Student.call(this, props);
  32. Sex.call(this, props);
  33. this.country = props.country;
  34. }
  35. /**
  36. * 多个对象的继承
  37. * @param {Constrctor} Children 需要继承多个类的构造函数-这里为People
  38. * @param {Json} Parents 多个需要被继承的构造函数
  39. * @explain 1 实例化构造函数得到的实例对象是{...} 这种类型的对象和JSON结构一样
  40. * @explain 2 Object.assign(target, ...sources) 通过ES5提供的复制可枚举对象实现
  41. */
  42. function inheritMore(Children, ...Parents) {
  43. // console.log(Parents);
  44. objAssigns(Children, Parents);
  45. Children.prototype.constrctor = Children;
  46. }
  47. /**
  48. * objAssigns 继承多个对象
  49. *
  50. * @param Children 需要继承多个类的构造函数-这里为People
  51. * @param {Array} Parents 多个需要被继承的构造函数构成的对象
  52. */
  53. function objAssigns(Children, Parents) {
  54. for (let i =0; i < Parents.length; i++) {
  55. Object.assign(Children.prototype, Parents[i].prototype);
  56. }
  57. }
  58. inheritMore(People, Student, Sex);
  59. const jeson = new People({
  60. guide: 'web前端',
  61. country: '中国',
  62. sex: '男',
  63. class: '3-6'
  64. });
  65. People.prototype.showCountry = function() {
  66. log(this.country);
  67. }
  68. jeson.showGuide(); // => 'web前端'
  69. jeson.showSex(); // => '男'
  70. jeson.showCountry(); // => '中国'
  71. log(jeson instanceof Student); // => false
  72. log(jeson instanceof Sex); // => false
  73. log(jeson instanceof People); // => true
  74. /**
  75. * 父类扩展看子类是否继承
  76. */
  77. Student.prototype.showClass = function() {
  78. log(this.class);
  79. }
  80. let tom = new People({
  81. class: '6-6'
  82. })
  83. Object.assign(People.prototype, Student.prototype); // 加上这句才能继承到父类扩展后的方法
  84. tom.showClass(); // => '6-6'

分析 back

  • 1 通过遍历多次Object.assin()完成多个对象的继承 参考4
  • 2 是否可以通过多次创建空函数的方式实现多对象继承呢?实际是不可以的,子类的原型对象只会为最后一个类的实例对象,前面都被覆盖了,具体请看参考6
  • 3 (优化)这种方式在继承父对象后,如果父对象扩展了某个方法,子对象需要再次继承,是否可以自动继承父类扩展的方法,不用再次继承父类呢?知道的道友可以留言

参考资料

Back

JS类继承常用方式发展史的更多相关文章

  1. Js 类继承 extends

    html 及 js 代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ...

  2. js实现继承的方式总结

    js实现继承的5种方式 以下 均为 ES5 的写法: js是门灵活的语言,实现一种功能往往有多种做法,ECMAScript没有明确的继承机制,而是通过模仿实现的,根据js语言的本身的特性,js实现继承 ...

  3. js对象的几种创建方式和js实现继承的方式[转]

    一.js对象的创建方式 1. 使用Object构造函数来创建一个对象,下面代码创建了一个person对象,并用两种方式打印出了Name的属性值. var person = new Object(); ...

  4. JS对象创建常用方式及原理分析

    ====此文章是稍早前写的,本次属于文章迁移@2017.06.27==== 前言 俗话说"在js语言中,一切都对象",而且创建对象的方式也有很多种,所以今天我们做一下梳理 最简单的 ...

  5. js的继承实现方式

    1. 使用call或者apply来实现js对象继承 function Animal(age){ this.age = age; this.say = function(){ console.log(' ...

  6. js实现继承的方式

    [原文] 前言 JS作为面向对象的弱类型语言,继承也是其非常强大的特性之一.那么如何在JS中实现继承呢?让我们拭目以待. JS继承的实现方式 既然要实现继承,那么首先我们得有一个父类,代码如下: // ...

  7. js 类继承extends

    先看例子: <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <titl ...

  8. js类继承扩展super

    相应的资料https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/super 例子: class Pol ...

  9. smartjs 0.2 OOP讲解 - Klass 类继承

    SmartJS2.0加入OOP的功能.OOP包括klass与factory两个对象. Klass 类继承 与其他的类继承相比,smartjs使用了执行指针的概念(后面例子中会介绍),另外提供base基 ...

随机推荐

  1. Xamarin介绍

    郑重声明: 本文非Xamarin使用详解,也没什么有用的干货,只是给不知道Xamarin到底是什么的大家提供一点点微不足道的小介绍,看完以后啥收获都没有也不是没可能的(*/ω\*).so......ε ...

  2. ssh keys管理工具

    原文地址:https://rtyan.github.io/%E5%B7%A5%E5%85%B7/2017/09/12/ssh-keys-manager.html 引言 我有两个github账户,一个是 ...

  3. MySQL的JOIN(四):JOIN优化实践之快速匹配

    这篇博文讲述如何优化扫描速度.我们通过MySQL的JOIN(二):JOIN原理得知了两张表的JOIN操作就是不断从驱动表中取出记录,然后查找出被驱动表中与之匹配的记录并连接.这个过程的实质就是查询操作 ...

  4. 数据库学习任务二:数据库连接对象SqlConnection

    数据库应用程序的开发流程一般主要分为以下几个步骤: 创建数据库 使用Connection对象连接数据库 使用Command对象对数据源执行SQL命令并返回数据 使用DataReader和DataSet ...

  5. 09 Linear Regression

    线性回归假设 错误衡量/代价函数---均方误差 最小化样本内代价函数 只有满秩方阵才有逆矩阵 线性回归算法 线性回归算法是隐式迭代的 线性回归算法泛化可能的保证 线性分类是近似求解,线性回归是解析求解 ...

  6. vmware 遇到 “无法打开内核设备 \\.\Global\vmx86” 解决

    问题描述:vmware没有正常关闭,再次打开使用时蓝屏,在安全模式下再次打开不会蓝屏,但提示"无法打开内核设备 \.\Global\vmx86: 系统找不到指定的文件,你想要安装VMware ...

  7. 201521123032《Java程序设计》第5周学习总结

    1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 1.2 可选:使用常规方法总结其他上课内容. 参考资料: 百度脑图 XMind 2. 书面作业 作业参考文件下载 1. 代码阅 ...

  8. 201521123088《JAVA程序设计》第5周学习总结

    1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 2. 书面作业 阅读:Child压缩包内源代码 1.1 com.parent包中Child.java文件能否编译通过?哪句会出 ...

  9. Java多态总结

    面向对象的三大特性:封装.继承.多态.从一定角度来看,封装和继承几乎都是为多态而准备的.这是我们最后一个概念,也是最重要的知识点. 1.定义: 多态:指允许不同类的对象对同一消息做出响应.即同一消息可 ...

  10. lintcode.66 二叉树前序遍历

    二叉树的前序遍历    描述 笔记 数据 评测 给出一棵二叉树,返回其节点值的前序遍历. 您在真实的面试中是否遇到过这个题? Yes 样例 给出一棵二叉树 {1,#,2,3}, 1 \ 2 / 3 返 ...