目的:
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()
分段解析
- _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,最后设置该属性及属性描述。
返回对象。
- _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)
}
- _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,应该使用新的语法来做继承。