Babel to Class之编译(1)
前言
这是《Babel to Class》系列的第一篇
这个系列主要讲 Class 的普通写法、继承、私有属性和原生构造函数继承 babel
是如何实现这一过程的。
注:文章顺序存在关联,请按照顺序阅读。
前置知识点
Object.defineProperty
Object.defineProperty(obj, prop, descriptor)
用于定义对象属性,它有三个参数分为别:对象,对象 key,以及属性描述符。
属性描述符默认不传递具体的值则为 false
const a = {};
Object.defineProperty(a, 'd', {});
Object.getOwnPropertyDescriptor(a, 'd');
// {value: undefined, writable: false, enumerable: false, configurable: false}
有两种调用形式
var o = {};
// 1.
Object.defineProperty(o, 'a', {
value: 37,
writable: true,
enumerable: true,
configurable: true,
});
// 2.
var bValue = 38;
Object.defineProperty(o, 'b', {
get() {
return bValue;
},
set(newValue) {
bValue = newValue;
},
enumerable: true,
configurable: true,
});
更多内容,以及属性描述符包含那些,请参考文档
Class
Class
必须通过new
调用,否则抛出Uncaught TypeError: Class constructor A cannot be invoked without 'new'
Class
的prototype
属性默认不可遍历
示例文件
class Test {
constructor() {
this.name = '张三';
}
_age = 18;
get age() {
return this._age;
}
set age(value) {
this._age = value;
}
getName() {
return this.name;
}
static getClassName() {
return this.name;
}
static name = 'TestClass';
}
上面就是准备好的示例文件,结构很简单,我们看下 babel
会将代码转码成什么样
babel
为了方便讲解,下面通过注释的形式来解读,阅读部分请从 const Test = /* #__PURE__ */ (function () {
这段开始。
'use strict';
function _classCallCheck(instance, Constructor) {
/*
* Class必须通过new调用,这是判断调用的this跟Test进行instanceof对比,如果不符合抛出错误
*/
if (!(instance instanceof Constructor)) {
throw new TypeError('Cannot call a class as a function');
}
}
/**
* 用于给对象定义属性
* 注意它判断了value属性是否存在,这是因为存在两种写法
* 一种是传递value的普通
* 另外一种是传递get和set的形式
*/
function _defineProperties(target, props) {
for (let i = 0; i < props.length; i++) {
const descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ('value' in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
/**
* 初始化Class属性
* 先从函数的prototype属性来进行定义
* 后面定义Constructor本身的属性
*/
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
Object.defineProperty(Constructor, 'prototype', { writable: false });
return Constructor;
}
/**
* 用于给Test实例和本身定义属性
* 之所以进行一个 in 判定是为了覆盖本身已经有的属性
* 例如class.name属性,这个本身已经存在 {value: 'A', writable: false, enumerable: false, configurable: true}
* 但是我们从新定义就要属性描述符全部为true
*/
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true });
} else {
obj[key] = value;
}
return obj;
}
const Test = /* #__PURE__ */ (function () {
function Test() {
// 初始进行new调用判断
_classCallCheck(this, Test);
// 实例属性写法
_defineProperty(this, '_age', 18);
this.name = '张三';
}
// 初始化,后面分为为prototype属性以及静态属性
_createClass(
Test,
[
{
key: 'age',
get: function get() {
return this._age;
},
set: function set(value) {
this._age = value;
},
},
{
key: 'getName',
value: function getName() {
return this.name;
},
},
],
[
{
key: 'getClassName',
value: function getClassName() {
return this.name;
},
},
],
);
return Test;
})();
_defineProperty(Test, 'name', 'TestClass');
概况一下上面流程:
- 初始化
Class
上的prototype 属性
以及static 属性
new Class
的时候,对 Class 的调用形式进行判断new
过程中赋值实例属性- 执行...
最后
如果有什么不正确或者书写错误欢迎指出。