Dieses Mal werde ich Ihnen die Implementierung der Babel-Konvertierung in es6 vorstellen. Was sind die Vorsichtsmaßnahmen für die Babel-Konvertierung in es6? Das Folgende ist ein praktischer Fall.
In unseren Projekten konvertieren wir alle bestimmte Codes wie env, stage-0 usw., indem wir Plug-Ins und Presets (eine Sammlung mehrerer Plug-Ins) konfigurieren.
Tatsächlich kann Babel jeden Code über benutzerdefinierte Plug-ins konvertieren. Als Nächstes lernen wir Babel anhand eines Beispiels für die „Konvertierung von class
von es6 in es5“ kennen.
Der Inhalt ist wie folgt:
Webpack-Umgebungskonfiguration
Jeder sollte den Babel-Core-Loader und seine konfiguriert haben Rolle Es stellt die Kern-API von Babel bereit. Tatsächlich wird unsere Codekonvertierung über Plug-Ins implementiert.
Als nächstes implementieren wir selbst ein ES6-Klassenkonvertierungs-Plug-In, ohne Plug-Ins von Drittanbietern zu verwenden. Führen Sie zunächst die folgenden Schritte aus, um ein Projekt zu initialisieren:
npm install webpack webpack-cli babel-core -D
Erstellen Sie ein neues Webpack. config. js
Webpack.config.js konfigurieren
Wenn unser Plug-in-Name „transform-class“ heißen soll, müssen wir das tun Nehmen Sie die folgende Konfiguration in der Webpack-Konfiguration vor:
Als nächstes erstellen wir einen neuen Ordner von babel-plugin-transform-class in node_modules Schreiben Sie die Logik des Plug-Ins (wenn Sie für ein echtes Projekt dieses Plug-In schreiben und im npm-Repository veröffentlichen müssen), wie unten gezeigt:
Der rote Bereich ist mein neu erstellter Ordner und darüber ein Standard-Plug-In. Für die Projektstruktur habe ich der Einfachheit halber nur die Kerndatei index.js geschrieben.
So schreiben Sie das Babel-Plug-In
Das Babel-Plug-In wird tatsächlich über AST (Abstract Syntax Tree) implementiert.
babel hilft uns, js-Code in AST zu konvertieren, ermöglicht uns dann, ihn zu ändern und ihn schließlich in js-Code zu konvertieren.
Es stellen sich also zwei Fragen: Wie ist die Zuordnungsbeziehung zwischen js-Code und AST? Wie ersetze oder füge ich ein neues AST hinzu?
Okay, stellen wir zuerst ein Tool vor: astexplorer.net:
Dieses Tool kann einen Code in AST konvertieren:
Wie in der Abbildung gezeigt, haben wir eine es6-Klasse geschrieben und dann auf der rechten Seite der Webseite einen AST für uns generiert, der tatsächlich jede Codezeile in ein Objekt umwandelt, sodass wir eine Zuordnung implementiert haben.
Wir stellen ein weiteres Dokument vor: babel-types:
Dies ist das API-Dokument zum Erstellen von AST-Knoten.
Wenn wir beispielsweise eine Klasse erstellen möchten, konvertieren wir sie zunächst in astexplorer.net und stellen fest, dass der der Klasse entsprechende AST-Typ ClassDeclaration
ist. Okay, lassen Sie uns in der Dokumentation suchen und feststellen, dass es ausreicht, nur die folgende API aufzurufen:
Dasselbe gilt für das Erstellen anderer Anweisungen Es wurden Umbauten vorgenommen.
Jetzt beginnen wir mit dem eigentlichen Schreiben eines Plug-Ins, das in die folgenden Schritte unterteilt ist:
Eine Funktion in index.js exportieren
Die Funktion gibt ein Objekt zurück und das Objekt verfügt über einen Besucherparameter (muss Besucher genannt werden)
Abfrage über astexplorer.netclass
Der entsprechende AST-Knoten ist ClassDeclaration
Legen Sie eine Erfassungsfunktion ClassDeclaration
in Vistor fest, was bedeutet, dass ich alle ClassDeclaration
Knoten im js-Code
module.exports = function ({ types: t }) { return { visitor: { ClassDeclaration(path) { //在这里完成转换 } } }; }
Schritt besteht darin, die{types:t}
Variable zu dekonstruieren t aus den Parametern, es ist tatsächlich t im Babel-Types-Dokument (rotes Kästchen im Bild unten), das zum Erstellen von Knoten verwendet wird:
第二个参数 path
,它是捕获到的节点对应的信息,我们可以通过 path.node
获得这个节点的AST,在这个基础上进行修改就能完成了我们的目标。
如何把es6的class转换为es5的类
上面都是预备工作,真正的逻辑从现在才开始,我们先考虑两个问题:
我们要做如下转换,首先把es6的类,转换为es5的类写法(也就是普通函数),我们观察到,很多代码是可以复用的,包括函数名字、函数内部的代码块等。
如果不定义class中的 constructor
方法,JavaScript引擎会自动为它添加一个空的 constructor()
方法,这需要我们做兼容处理。
接下来我们开始写代码,思路是:
拿到老的AST节点
创建一个数组用来盛放新的AST节点(虽然原class只是一个节点,但是替换后它会被若干个函数节点取代) 初始化默认的 constructor
节点(上文提到,class中有可能没有定义constructor)
循环老节点的AST对象(会循环出若干个函数节点)
判断函数的类型是不是 constructor
,如果是,通过取到数据创建一个普通函数节点,并更新默认 constructor
节点
处理其余不是 constructor
的节点,通过数据创建 prototype
类型的函数,并放到 es5Fns
中
循环结束,把 constructor
节点也放到 es5Fns
中
判断es5Fns的长度是否大于1,如果大于1使用 replaceWithMultiple
这个API更新AST
module.exports = function ({ types: t }) { return { visitor: { ClassDeclaration(path) { //拿到老的AST节点 let node = path.node let className = node.id.name let classInner = node.body.body //创建一个数组用来成盛放新生成AST let es5Fns = [] //初始化默认的constructor节点 let newConstructorId = t.identifier(className) let constructorFn = t.functionDeclaration(newConstructorId, [t.identifier('')], t.blockStatement([]), false, false) //循环老节点的AST对象 for (let i = 0; i < classInner.length; i++) { let item = classInner[i] //判断函数的类型是不是constructor if (item.kind == 'constructor') { let constructorParams = item.params.length ? item.params[0].name : [] let newConstructorParams = t.identifier(constructorParams) let constructorBody = classInner[i].body constructorFn = t.functionDeclaration(newConstructorId, [newConstructorParams], constructorBody, false, false) } //处理其余不是constructor的节点 else { let protoTypeObj = t.memberExpression(t.identifier(className), t.identifier('prototype'), false) let left = t.memberExpression(protoTypeObj, t.identifier(item.key.name), false) //定义等号右边 let prototypeParams = classInner[i].params.length ? classInner[i].params[i].name : [] let newPrototypeParams = t.identifier(prototypeParams) let prototypeBody = classInner[i].body let right = t.functionExpression(null, [newPrototypeParams], prototypeBody, false, false) let protoTypeExpression = t.assignmentExpression("=", left, right) es5Fns.push(protoTypeExpression) } } //循环结束,把constructor节点也放到es5Fns中 es5Fns.push(constructorFn) //判断es5Fns的长度是否大于1 if (es5Fns.length > 1) { path.replaceWithMultiple(es5Fns) } else { path.replaceWith(constructorFn) } } } }; }
优化继承
其实,类还涉及到继承,思路也不复杂,就是判断AST中没有 superClass
属性,如果有的话,我们需要多添加一行代码 Bird.prototype = <a href="http://www.php.cn/wiki/60.html" target="_blank">Object</a>.create(Parent)
,当然别忘了处理 super
关键字。
打包后代码
运行 npm start
打包后,我们看到打包后的文件里 class
语法已经成功转换为一个个的es5函数。
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
Das obige ist der detaillierte Inhalt vonImplementierung der Babel-Konvertierung der es6-Methode. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!