• js-es6-class转es5源码解析


    目的:
    1、es6 class 转为 es5 的源码及如何实现继承
    2、手写继承和Class的不同之处。

    安装babel

    npm install -g babel-cli

    npm init -y

    npm install --save-dev babel-preset-es2015 babel-cli

    新建.babelrc

    {
      "presets": ["es2015"],
      "plugins": []
    }
    
    • 1
    • 2
    • 3
    • 4

    package.json添加:

      ...
      "dev": "babel src -d dist"
      ...
    
    • 1
    • 2
    • 3

    新建目录src,dist。

    新建文件src/index.js

    "use strict"
    class Base {
      constructor() {
        this.a = 1
      }
      f1() {
        console.log(this.a)
      }
    }
    class Cls extends Base{
      constructor(props) {
        super(props)
        this.a = 2
      }
      f1() {
        console.log(this.a)
      }
    }
    let cls = new Cls()
    cls.f1()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    npm run dev

    查看es5源码

    'use strict'
    
    var _createClass = (function () {
      function defineProperties(target, props) {
        for (var i = 0; i < props.length; i++) {
          var descriptor = props[i]
          descriptor.enumerable = descriptor.enumerable || false
          descriptor.configurable = true
          if ('value' in descriptor) descriptor.writable = true
          Object.defineProperty(target, descriptor.key, descriptor)
        }
      }
      return function (Constructor, protoProps, staticProps) {
        if (protoProps) defineProperties(Constructor.prototype, protoProps)
        if (staticProps) defineProperties(Constructor, staticProps)
        return Constructor
      }
    })()
    
    function _possibleConstructorReturn(self, call) {
      if (!self) {
        throw new ReferenceError(
          "this hasn't been initialised - super() hasn't been called"
        )
      }
      return call && (typeof call === 'object' || typeof call === 'function')
        ? call
        : self
    }
    
    function _inherits(subClass, superClass) {
      if (typeof superClass !== 'function' && superClass !== null) {
        throw new TypeError(
          'Super expression must either be null or a function, not ' +
            typeof superClass
        )
      }
      subClass.prototype = Object.create(superClass && superClass.prototype, {
        constructor: {
          value: subClass,
          enumerable: false,
          writable: true,
          configurable: true,
        },
      })
      if (superClass)
        Object.setPrototypeOf
          ? Object.setPrototypeOf(subClass, superClass)
          : (subClass.__proto__ = superClass)
    }
    
    function _classCallCheck(instance, Constructor) {
      if (!(instance instanceof Constructor)) {
        throw new TypeError('Cannot call a class as a function')
      }
    }
    
    var Base = (function () {
      function Base() {
        _classCallCheck(this, Base)
    
        this.a = 1
      }
    
      // 设置Base类的属性
      _createClass(Base, [
        {
          key: 'f1',
          value: function f1() {
            console.log(this.a)
          },
        },
      ])
    
      return Base
    })()
    
    var Cls = (function (_Base) {
      _inherits(Cls, _Base) // 实现继承
    
      function Cls(props) {
        _classCallCheck(this, Cls)
    
        // 获取构造器返回的this
        var _this = _possibleConstructorReturn(
          this,
          (Cls.__proto__ || Object.getPrototypeOf(Cls)).call(this, props)
        )
    
        _this.a = 2
        return _this
      }
    
      // 同Base
      _createClass(Cls, [
        {
          key: 'f1',
          value: function f1() {
            console.log(this.a)
          },
        },
      ])
    
      return Cls
    })(Base)
    
    var cls = new Cls()
    cls.f1()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109

    分段解析

    1. _classCallCheck 检查是否是继承关系
    function _classCallCheck(instance, Constructor) {
      if (!(instance instanceof Constructor)) {
        throw new TypeError('Cannot call a class as a function')
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    传入this和类名
    检查类是否被当作函数使用
    2. _createClass 新建一个类对象

    var _createClass = (function () {
      function defineProperties(target, props) {
        for (var i = 0; i < props.length; i++) {
          var descriptor = props[i]
          descriptor.enumerable = descriptor.enumerable || false
          descriptor.configurable = true
          if ('value' in descriptor) descriptor.writable = true
          Object.defineProperty(target, descriptor.key, descriptor)
        }
      }
      return function (Constructor, protoProps, staticProps) {
        if (protoProps) defineProperties(Constructor.prototype, protoProps)
        if (staticProps) defineProperties(Constructor, staticProps)
        return Constructor
      }
    })()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    设置类的属性及静态属性,属性放在构造器的原型函数上,静态属性放在构造器上。
    设置属性的可枚举性(默认为false)、可配置性为true,有value则设置可写属性为true,最后设置该属性及属性描述。
    返回对象。

    1. _inherits 继承的实现
    function _inherits(subClass, superClass) {
      // 基类不能是null或者函数
      if (typeof superClass !== 'function' && superClass !== null) {
        throw new TypeError(
          'Super expression must either be null or a function, not ' +
            typeof superClass
        )
      }
      // 有基类则将子类原型指向基类原型,实现对象浅复制,并且将构造器指向自己。
      subClass.prototype = Object.create(superClass && superClass.prototype, {
        constructor: {
          value: subClass,
          enumerable: false,
          writable: true,
          configurable: true,
        },
      })
      // 有继承,判断是否有Object.setPrototypeOf方法,有则使用Object.setPrototypeOf设置两者的继承关系。否则使用__proto__来实现继承。
      if (superClass)
        Object.setPrototypeOf
          ? Object.setPrototypeOf(subClass, superClass)
          : (subClass.__proto__ = superClass)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    1. _possibleConstructorReturn 根据构造函数返回this执向。
    function _possibleConstructorReturn(self, call) {
      if (!self) {
        throw new ReferenceError(
          "this hasn't been initialised - super() hasn't been called"
        )
      }
      // 有使用super(props)则调用this的原型,并传入参数,最后返回这个原型作为新的this
      // 没有调用则返回本身的this
      return call && (typeof call === 'object' || typeof call === 'function')
        ? call
        : self
    }
    // 调用
    // 传入(1)this (2)调用子类的原型函数并传入参数
     var _this = _possibleConstructorReturn(
          this,
          (Cls.__proto__ || Object.getPrototypeOf(Cls)).call(this, props)
        )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    Class Cls
    在这里插入图片描述

    • 类型:
      node中打印结果:[class Base] [class Cls extends Base]
      浏览器中打印结果:function 类型

    • 关键字:
      class Cls

    • 结构:
      有原型对象和原型链
      原型对象指向Base,Base的构造器指向Cls,循环引用。有f1方法

      按照原型链来看:

      原型链指向Base。
      Base只有原型对象,没有构造函数
      Base的原型链指向Function

    源码Cls

    在这里插入图片描述

    • 类型:
      node中打印结果:[Function: Cls]
      浏览器中打印结果:function 类型

    • 关键字:
      f Cls

    • 结构:
      属性不是在原型上,而是在自身。
      没有原型对象,只有原型链

      按照原型链来看:

      原型链指向Base。
      Base的构造函数是Cls(props),并带有f1方法。
      new Cls的时候,构造函数指向CLs,说明实例是Cls生成的,原型链指向继承的类。整体形成完整的语义化。

      Base的原型链指向Object
      Object的构造函数是Base(),并带有f1方法。

      Object的原型链指向Object,
      Object的构造器是Object()

    总结:
    class语法糖中,还是按照老式的寄生组合的方法去实现继承。
    而使用es6新增的函数(object.create(), object.setPrototypeof(cls, base))来创建类,则省去了原型对象,属性在自身,查找链短了(说明查找速度更快)。
    整体结构性和可读性更强。

    大白话:其实就是在问新的语法Object.create()和Object.setPrototype()的使用效果和原来继承的写法的比较,然后得出结论说现在的语法经过了改善,更加语义化,效率也提升了,不要再使用class,应该使用新的语法来做继承。

  • 相关阅读:
    XTTS系列之五:警惕大文件表空间
    区块链技术中的共识机制算法:以工作量证明(PoW)为例
    自动驾驶中的坐标系变换
    vue3动态路由警告问题
    layui 树状控件tree优化
    将模板声明为友元
    【C++入门系列】——命名空间和输入输出
    【20221028】【每日一题】左叶子之和
    MS14-068漏洞复现
    健身耳机哪些品牌好?健身运动耳机推荐
  • 原文地址:https://blog.csdn.net/junjiahuang/article/details/126724411