ES5的继承实现,这里以最佳实践:寄生组合式继承方式来实现。(为什么是最佳实践,前面有随笔讲过了,可以参考)

  1. function Super(name) {
  2. this.name = name;
  3. }
  4.  
  5. Super.prototype.sayName = function() {
  6. console.log(this.name)
  7. }
  8.  
  9. function Sub(name, age) {
  10. Super.call(this, name);
  11. this.age = age;
  12. }
  13.  
  14. Sub.prototype.sayAge = function() {
  15. console.log(this.age)
  16. }
  17.  
  18. Sub.prototype = Object.create(Super.prototype, {
  19. constructor: {
  20. value: Sub,
  21. writable: true,
  22. configurable: true
  23. }
  24. });

这里的Object.create可以替换成Object.setPrototypeOf,好处是不用再手动绑定constructor的指向。

这是ES5继承,再看下ES6的继承,同样实现上面的效果

  1. class Super {
  2. constructor(name) {
  3. this.name = name;
  4. }
  5. sayName() {
  6. console.log(this.name);
  7. }
  8. }
  9.  
  10. class Sub extends Super {
  11. constructor(name, age) {
  12. super(name);
  13. this.age = age;
  14. }
  15. sayAge() {
  16. console.log(this.age);
  17. }
  18. }

很明显,ES6的继承要更简洁点,那区别是什么?

我们看一下babel解析后的ES6的继承:

  1. "use strict";
  2.  
  3. function _typeof(obj) {
  4. if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
  5. _typeof = function _typeof(obj) {
  6. return typeof obj;
  7. };
  8. } else {
  9. _typeof = function _typeof(obj) {
  10. return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
  11. };
  12. } return _typeof(obj);
  13. }
  14.  
  15. function _possibleConstructorReturn(self, call) {
  16. if (call && (_typeof(call) === "object" || typeof call === "function")) {
  17. return call;
  18. } return _assertThisInitialized(self);
  19. }
  20.  
  21. function _assertThisInitialized(self) {
  22. if (self === void 0) {
  23. throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
  24. } return self;
  25. }
  26.  
  27. function _getPrototypeOf(o) {
  28. _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
  29. return o.__proto__ || Object.getPrototypeOf(o);
  30. }; return _getPrototypeOf(o);
  31. }
  32.  
  33. function _inherits(subClass, superClass) {
  34. if (typeof superClass !== "function" && superClass !== null) {
  35. throw new TypeError("Super expression must either be null or a function");
  36. }
  37. subClass.prototype = Object.create(superClass && superClass.prototype, {
  38. constructor: {
  39. value: subClass,
  40. writable: true,
  41. configurable: true
  42. }
  43. });
  44. if (superClass) _setPrototypeOf(subClass, superClass);
  45. }
  46.  
  47. function _setPrototypeOf(o, p) {
  48. _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
  49. o.__proto__ = p;
  50. return o;
  51. };
  52. return _setPrototypeOf(o, p);
  53. }
  54.  
  55. function _instanceof(left, right) {
  56. if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
  57. return !!right[Symbol.hasInstance](left);
  58. } else {
  59. return left instanceof right;
  60. }
  61. }
  62.  
  63. function _classCallCheck(instance, Constructor) {
  64. if (!_instanceof(instance, Constructor)) {
  65. throw new TypeError("Cannot call a class as a function");
  66. }
  67. }
  68.  
  69. function _defineProperties(target, props) {
  70. for (var i = 0; i < props.length; i++) {
  71. var descriptor = props[i];
  72. descriptor.enumerable = descriptor.enumerable || false;
  73. descriptor.configurable = true;
  74. if ("value" in descriptor) descriptor.writable = true;
  75. Object.defineProperty(target, descriptor.key, descriptor);
  76. }
  77. }
  78.  
  79. function _createClass(Constructor, protoProps, staticProps) {
  80. if (protoProps) _defineProperties(Constructor.prototype, protoProps);
  81. if (staticProps) _defineProperties(Constructor, staticProps);
  82. return Constructor;
  83. }
  84.  
  85. var Super =
  86. /*#__PURE__*/
  87. function () {
  88. function Super(name) {
  89. _classCallCheck(this, Super);
  90.  
  91. this.name = name;
  92. }
  93.  
  94. _createClass(Super, [{
  95. key: "sayName",
  96. value: function sayName() {
  97. console.log(this.name);
  98. }
  99. }]);
  100.  
  101. return Super;
  102. }();
  103.  
  104. var Sub =
  105. /*#__PURE__*/
  106. function (_Super) {
  107. _inherits(Sub, _Super);
  108.  
  109. function Sub(name, age) {
  110. var _this;
  111.  
  112. _classCallCheck(this, Sub);
  113.  
  114. _this = _possibleConstructorReturn(this, _getPrototypeOf(Sub).call(this, name));
  115. _this.age = age;
  116. return _this;
  117. }
  118.  
  119. _createClass(Sub, [{
  120. key: "sayAge",
  121. value: function sayAge() {
  122. console.log(this.age);
  123. }
  124. }]);
  125.  
  126. return Sub;
  127. }(Super);

代码有点多,但很多都是做了一些类型检查或者是polify的兼容,关键的方法是两个地方:

1,_inherits (这里等同于关键字extends的作用)

  1. function _inherits(subClass, superClass) {
  2. if (typeof superClass !== "function" && superClass !== null) {
  3. throw new TypeError("Super expression must either be null or a function");
  4. }
  5. subClass.prototype = Object.create(superClass && superClass.prototype, {
  6. constructor: {
  7. value: subClass,
  8. writable: true,
  9. configurable: true
  10. }
  11. });
  12. if (superClass) _setPrototypeOf(subClass, superClass);
  13. }

前面的和ES5继承没有区别,也是用了Object.create实现子类的prototype继承父类的prototype,但是最后多了一个操作

  1. _setPrototypeOf(subClass, superClass);

看一下对应的函数定义

  1. function _setPrototypeOf(o, p) {
  2. _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
  3. o.__proto__ = p;
  4. return o;
  5. };
  6. return _setPrototypeOf(o, p);
  7. }

意图很明显了,就是为了实现子类继承父类!

从这里我们看出差别了,ES6的继承除了子类的原型继承以外,还多了子类的自身继承父类,但是为什么这么做呢?

(这里笔者也没有想明白为什么要这么做,欢迎留言补充解惑!)

2,_possibleConstructorReturn (这里等同于super关键字)

  1. function _possibleConstructorReturn(self, call) {
  2. if (call && (_typeof(call) === "object" || typeof call === "function")) {
  3. return call;
  4. } return _assertThisInitialized(self);
  5. }
  6.  
  7. function _assertThisInitialized(self) {
  8. if (self === void 0) {
  9. throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
  10. } return self;
  11. }

看一下用法

  1. _this = _possibleConstructorReturn(this, _getPrototypeOf(Sub).call(this, name));

这里的 _getPrototypeOf(Sub) 实际上就是Super,因为上面使用了_inherits,所以已经继承了类,因此这里就是等同于在Sub的内部使用了Super.call(this, name);从而实现了属性的继承,因此和ES5是一样的。

  1.  

不过综上来看,确实ES6的继承要简单很多,主要是写法上比较简单,不用手动去实现原型的继承以及属性的复制,但是本质上其实是一样的。

end

ES5和ES6的继承对比的更多相关文章

  1. 详解ES5和ES6的继承

    ES5继承 构造函数.原型和实例的关系:每一个构造函数都有一个原型对象,每一个原型对象都有一个指向构造函数的指针,而每一个实例都包含一个指向原型对象的内部指针, 原型链实现继承 基本思想:利用原型让一 ...

  2. ES5与ES6的继承

    JavaScript本身是一种神马语言: 提到继承,我们常常会联想到C#.java等面向对象的高级语言(当然还有C++),因为存在类的概念使得这些语言在实际的使用中抽象成为一个对象,即面向对象.Jav ...

  3. ES5和ES6的继承

    ES5继承 构造函数.原型和实例的关系:每一个构造函数都有一个原型对象,每一个原型对象都有一个指向构造函数的指针,而每一个实例都包含一个指向原型对象的内部指针, 原型链实现继承 基本思想:利用原型让一 ...

  4. 一起手写吧!ES5和ES6的继承机制!

    原型 执行代码var o = new Object(); 此时o对象内部会存储一个指针,这个指针指向了Object.prototype,当执行o.toString()等方法(或访问其他属性)时,o会首 ...

  5. ES5和ES6中对于继承的实现方法

    在ES5继承的实现非常有趣的,由于没有传统面向对象类的概念,Javascript利用原型链的特性来实现继承,这其中有很多的属性指向和需要注意的地方. 原型链的特点和实现已经在之前的一篇整理说过了,就是 ...

  6. 多角度对比 ES5与ES6的区别

    ES5与ES6的对比不同点整理 本文关键词:ES6,javascript, 1.Default Parameters(默认参数) es6之前,定义默认参数的方法是在一个方法内部定义 var link ...

  7. ES5与ES6对比

    ES5与ES6对比 1. 模块引用 1.在ES5里,引入React包基本通过require进行,代码类似这样: // ES5 var React = require('react'); var { C ...

  8. React入门 (1)—使用指南(包括ES5和ES6对比)

    前言 本篇会简明扼要的介绍一下React的使用方法.代码会用JSX+ES5和JSX+ES6两种方式实现. React简介 React来自Facebook,于2013年开源.至今不断修改完善,现在已经到 ...

  9. JavaScript面向对象轻松入门之继承(demo by ES5、ES6)

    继承是面向对象很重要的一个概念,分为接口继承和实现继承,接口继承即为继承某个对象的方法,实现继承即为继承某个对象的属性.JavvaScript通过原型链来实现接口继承.call()或apply()来实 ...

随机推荐

  1. bzoj 2780 [Spoj]8093 Sevenk Love Oimaster

    LINK:Sevenk Love Oimaster 询问一个模式串在多少个文本串中出现过. 考虑广义SAM 统计这种数量问题一般有三种做法. 一种 暴力bitset 这道题可能可以过? 一种 暴力跳p ...

  2. Struts/Servlet,action转到jsp后,CSS失效,路径问题(struts2,jsp路径,action路径,action跳转,相对路径,绝对路径)

    问题:使用struts2,如何处理action的路径?还有,在action转到的jsp中,如何写js,css,图 片的路径?(例如访问http://localhost/project/listUser ...

  3. Navicat15安装教程

    本文内容皆为作者原创,如需转载,请注明出处:https://www.cnblogs.com/xuexianqi/p/12797170.html 一:简介 Navicat是一套快速.可靠的数据库管理工具 ...

  4. UI自动化填写问卷(selenium)+定时任务(懒人必备)

    1.自动填报 UI自动化 selenium 开发程序动机:天天有人催着填写问卷,弄的头大.主要还是懒的每天一个个去填写内容. 开发总时长:2个小时:学习+开发+修改 遇到的小问题: 在自动化填写地图的 ...

  5. Android Studio--家庭记账本(三)

    点击右上角可以实现将花费以折线图的形式显示出来.同时将同一天的花费自动计算.暂时还没有加x,y轴 ChartsActivity.java: package com.example.family; im ...

  6. CSS表单与数据表(下)

    2.表单 表单是用户输入内容的地方.表单涉及的控件很多,而且一直很难给它们应用样式.无法控制样式的部分,可以通过自定义控件来解决. 2.1 简单的表单 2.1.1 fieldset与legend fi ...

  7. FSAF

    Feature Selective Anchor-Free Module for Single-Shot Object Detection https://zhuanlan.zhihu.com/p/5 ...

  8. java 异常一

    一 异常的继承体系 在Java中使用Exception类来描述异常. 查看API中Exception的描述,Exception 类及其子类是 Throwable 的一种形式,它用来表示java程序中 ...

  9. 痞子衡嵌入式:一种i.MXRT下从App中进入ROM串行下载模式的方法

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT下在App中利用ROM API进ISP/SDP模式的方法. 我们知道i.MXRT系列分为两大阵营:CM33内核的i.MXRT ...

  10. 一文看懂 Netty 架构设计

    本文重点分析 Netty 的逻辑架构及关键的架构质量属性,希望有助于大家从 Netty 的架构设计中汲取营养,设计出高性能.高可靠性和可扩展的程序. Netty 的三层架构设计 Netty 采用了典型 ...