跳到主要内容

转换类

一、前言


转换前

class Person {
constructor(name) {
this.name = name;
}

getName() {
return this.name;
}
}

转换后

  • Babel官方转换

    function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a 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); } }

    function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }

    var Person = /*#__PURE__*/function () {
    function Person(name) {
    _classCallCheck(this, Person);

    this.name = name;
    }

    _createClass(Person, [{
    key: "getName",
    value: function getName() {
    return this.name;
    }
    }]);

    return Person;
    }();
  • ES5 简单转换

    function Person(name){
    this.name = name;
    }
    Person.prototype.getName = function(){
    return this.name;
    }

二、官方实现


const BabelCore = require("@babel/core");
const Types = require("babel-types");
const TransformClasses = require("@babel/plugin-transform-classes");

const sourceCode = `class Person {
constructor(name) {
this.name = name;
}

getName() {
return this.name;
}
};`;

const targetCode = BabelCore.transform(sourceCode, {
plugins: [TransformClasses],
});
console.log(targetCode.code);

三、模拟实现


3.1 分析语法树结构

ES6类语法树结构如下:

Preview
Preview

ES6类语法树结构如下:

Preview
Preview

3.2 实现类转换插件

const BabelCore = require("@babel/core");
const Types = require("babel-types");
const TransformClasses = require("@babel/plugin-transform-classes");

const sourceCode = `class Person {
constructor(name) {
this.name = name;
}

getName() {
return this.name;
}
};`;

const TransformClassesSelf = {
visitor: {
ClassDeclaration(nodePath) {
const { node } = nodePath;
const { id } = node;
const { body: classMethods } = node.body;
const nodes = [];
classMethods.forEach((classMethod) => {
if (classMethod.kind === 'constructor') {
const constructor = Types.functionDeclaration(id, classMethod.params, classMethod.body);
nodes.push(constructor);
} else {
const rightExpression = Types.functionExpression(null, classMethod.params, classMethod.body);
const prototypeExpression = Types.memberExpression(id, Types.identifier('prototype'));
const memberExpression = Types.memberExpression(prototypeExpression, classMethod.key);
const assignmentExpression = Types.assignmentExpression('=', memberExpression, rightExpression);
nodes.push(assignmentExpression);
}
});
if (nodes.length === 1) {
nodePath.replaceWith(nodes[0]);
} else {
nodePath.replaceWithMultiple(nodes);
}
},
},
};

const targetCode = BabelCore.transform(sourceCode, {
plugins: [TransformClassesSelf],
});
console.log(targetCode.code);