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": []
}

package.json添加:

  ...
  "dev": "babel src -d dist"
  ...

新建目录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()

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. _classCallCheck 检查是否是继承关系
function _classCallCheck(instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError('Cannot call a class as a function')
  }
}

传入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
  }
})()

设置类的属性及静态属性,属性放在构造器的原型函数上,静态属性放在构造器上。
设置属性的可枚举性(默认为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. _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)
    )

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,应该使用新的语法来做继承。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值