Heim >Web-Frontend >js-Tutorial >Schreiben Sie einen JS-Interpreter mit JavaScript
Die Verwendung von js 编译 js
scheint eine High-End-Sache zu sein, aber das eigentliche Prinzip ist eigentlich sehr einfach. Es ist nichts weiter als schwarze Magie, die durch die Verwendung der Funktion von js 对象属性可以用字符串表示
realisiert wird. Der Grund, warum
so aussieht 深奥
, liegt wahrscheinlich darin, dass die vorhandenen Tutorials im Internet immer zuerst einen babylon / @babel/parser
geben, allen eine große Liste von AST
zeigen und dann eine große Liste davon veröffentlichen ,
Direkt rekursiver AST zur Verarbeitung aller Knotentypen Am Ende wurden Anfänger erfolgreich abgeschreckt.
Der Zweck des heutigen Schreibens dieses Artikels besteht darin, Ihnen ein js2js-Tutorial zu geben, das leicht zu verstehen ist und auch von denen verstanden werden kann, die js gerade erst gelernt haben.
Werfen wir zunächst einen Blick auf den Effekt
Wie oben erwähnt, verfügt js über eine Funktion, die, zum Beispiel ist console.log äquivalent zu console['log'], also können wir basierend auf dieser Funktion einen extrem schlechten und groben Prototyp schreiben 对象属性可以用字符串表示
function callFunction(fun, arg) { this[fun](arg); } callFunction('alert', 'hello world'); // 如果你是在浏览器环境的话,应该会弹出一个弹窗Da es sich um eine vereinfachte Version handelt, muss es so sein Es gibt viele Probleme bei der Syntax in js. Sehen wir uns an, wie die Zuweisung mit schwarzer Magie implementiert wird.
function declareVarible(key, value) { this[key] = value; } declareVarible.call(window, 'foo', 'bar'); // window.foo = 'bar'
Tipps: const kann mit Object.defineProperty;Wenn Sie den obigen Code verstehen, bedeutet das, dass Sie die Grundprinzipien vonimplementiert werden
bereits verstehen. Wenn Sie ihn nicht verstehen, können Sie mir nur die Schuld geben. js 解释器
geschrieben, aber er sieht überhaupt nicht wie callFunction('alert', 'hello world');
aus, js 解释器
in In unserem Kopf sollte der gewünschte Interpreter mindestens so aussehen
, also nehmen wir eine kleine Änderung vor. Hier müssen wir Babel einführen, parse('alert("hello world")'')
aber keine Sorge, der von uns analysierte Syntaxbaum (AST) ist auch sehr einfach von.
import babelParser from '@babel/parser'; const code = 'alert("hello world!")'; const ast = babelParser.parse(code);Der obige Code analysiert den folgenden Inhalt
{ "type": "Program", "start": 0, "end": 21, "body": [ { "type": "ExpressionStatement", "start": 0, "end": 21, "expression": { "type": "CallExpression", "start": 0, "end": 21, "callee": { "type": "Identifier", "start": 0, "end": 5, "name": "alert" }, "arguments": [ { "type": "Literal", "start": 6, "end": 20, "value": "hello world!", "raw": "\"hello world!\"" } ] } } ], "sourceType": "module" }Der obige Inhalt scheint viel zu sein, aber was wir tatsächlich verwenden, ist eigentlich nur ein kleiner Teil. Vereinfachen wir ihn ein wenig und speichern wir ihn die Dinge, die vorerst nicht benötigt werden. Entfernen Sie die Felder, die zuerst eintreffen
{ "type": "Program", "body": [ { "type": "ExpressionStatement", "expression": { "type": "CallExpression", "callee": { "type": "Identifier", "name": "alert" }, "arguments": [ { "type": "Literal", "value": "hello world!", } ] } } ], }Lassen Sie uns zunächst alle Daten mit Attributnamen
im AST type
{ "type": "Literal", "value": "hello world!", }
if(node.type === 'Literal') { return node.value; }Ist es nicht ganz einfach? Bezeichner
{ "type": "Identifier", "name": "alert" },
if(node.type === 'Identifier') { return { name: node.name, value:this[node.name] }; }Das obige
, das wir von alert
erhalten, ist ein Zeichen, über node.name
können wir auf den Bezeichner (Identifier) this['xxxxx']
ExpressionStatement
{ "type": "ExpressionStatement", "expression": {...} }
if(node.type === 'ExpressionStatement') { return parseAstNode(node.expression); }
expression
CallExpressionCallExpression bedeutet wörtlich ein Funktionsaufrufausdruck, was etwas problematischer ist{ "type": "CallExpression", "callee": {...}, "arguments": [...] }
callee ist ein Verweis auf die Funktion, und der Inhalt darin ist ein Bezeichner, der mit der oben genannten Methode verarbeitet werden kann. Der Inhalt in den
if(node.type === 'CallExpression') { // 函数 const callee = 调用 Identifier 处理器 // 参数 const args = node.arguments.map(arg => { return 调用 Literal 处理器 }); callee(...args); }
Skript-DOM einfügen
const script = document.createElement("script"); script.innerText = 'alert("hello world!")'; document.body.appendChild(script);
eval('alert("hello world!")')
new Function('alert("hello world")')();
setTimeout('console.log("hello world")');
(Front-End-Informationsaustausch), egal wo auf der Welt Sie sind,
egal wie viele Jahre Sie schon arbeiten, Sie sind herzlich willkommen, beizutreten! (Die Gruppe stellt regelmäßig kostenlose Lernbücher und Materialien zur Verfügung, die vom Gruppeninhaber gesammelt wurden, sowie zusammengestellte Interviewfragen und Antwortdokumente!) Wenn Sie Einwände gegen diesen Artikel haben, schreiben Sie bitte im Kommentarbereich des Schreiben Sie Ihre Kommentare.
Ich hoffe, dass jeder auf dem Weg des Programmierens immer weiter vorankommen kann.
Empfohlenes Tutorial: „JS-Tutorial“
Das obige ist der detaillierte Inhalt vonSchreiben Sie einen JS-Interpreter mit JavaScript. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!