js を使用して js をコンパイルする
高機能に見えますが、実際の原理は非常に単純です。js を使用することに他なりません オブジェクトのプロパティは文字列で表現できます
この機能はまさに黒魔術で実装されています。
これが非常に深いように見える理由は、おそらく、インターネット上の既存のチュートリアルが常に babylon / @babel/parser
で始まるからです。最初に皆さんに見てもらいましょう。長いリストAST
のコード、およびコードの長いリスト、 を直接再帰的に AST してあらゆるタイプのノードを処理します。
そこで今日この記事を書く目的は、jsを学び始めたばかりの人でも理解できる、分かりやすいjs2jsのチュートリアルを提供することです。
最初に効果を見てみましょう
最も単純なインタプリタ
, たとえば、console.log は console['log'] と同等です。この機能に基づいて、互換性の低い非常に粗雑なプロトタイプを作成できます。<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false"> function callFunction(fun, arg) {
this[fun](arg);
}
callFunction('alert', 'hello world');
// 如果你是在浏览器环境的话,应该会弹出一个弹窗</pre><div class="contentsignin">ログイン後にコピー</div></div>
は単純なバージョンです。問題はたくさんあるはずです。js の構文は関数呼び出しだけではありません。黒魔術を使用して代入がどのように実装されるかを見てみましょう。
function declareVarible(key, value) { this[key] = value; } declareVarible.call(window, 'foo', 'bar'); // window.foo = 'bar'
上記のコードを理解できれば、js インタープリター
の基本原理はすでに理解していることになります。あなたは私を責めなければなりません。 少し強化してください
として記述しましたが、見てください、これは js インタープリターのようには見えません
,私たちが必要とするインタープリターは少なくとも次のようになるはずです
parse('alert("hello world")'')
それでは、少し修正を加えてみましょう。ここで babel を導入する必要があります。しかし、まだ心配する必要はありません。解析する構文ツリー (AST) も非常に単純です。
import babelParser from '@babel/parser'; const code = 'alert("hello world!")'; const ast = babelParser.parse(code);
{ "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" }
上記のコンテンツはたくさんあるように見えますが、実際に使用するのは実際にはほんの一部です。最初に到達したフィールドを削除します
{ "type": "Program", "body": [ { "type": "ExpressionStatement", "expression": { "type": "CallExpression", "callee": { "type": "Identifier", "name": "alert" }, "arguments": [ { "type": "Literal", "value": "hello world!", } ] } } ], }
まず、AST
ExpressionStatement
の属性名
Literal
{ "type": "Literal", "value": "hello world!", }
if(node.type === 'Literal') { return node.value; }
非常に単純ではないでしょうか。
Identifier
{ "type": "Identifier", "name": "alert" },
if(node.type === 'Identifier') { return { name: node.name, value:this[node.name] }; }
から取得した上記の alert
は文字であり、this['xxxxx']
を通じてアクセスできます。現在のスコープ内の識別子 (Identifier) に変換します (ここがウィンドウです)ExpressionStatement
{ "type": "ExpressionStatement", "expression": {...} }
属性を使用するため、expression の内容を直接返すことができます<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">if(node.type === 'ExpressionStatement') {
return parseAstNode(node.expression);
}</pre><div class="contentsignin">ログイン後にコピー</div></div>
CallExpression
{ "type": "CallExpression", "callee": {...}, "arguments": [...] }
CallExpression には必要なフィールドが 2 つあります。
callee は関数への参照で、内部のコンテンツは識別子であり、上記のメソッドを使用して処理できます。if(node.type === 'CallExpression') { // 函数 const callee = 调用 Identifier 处理器 // 参数 const args = node.arguments.map(arg => { return 调用 Literal 处理器 }); callee(...args); }
##挿入スクリプト DOM
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")');
この記事が興味深いと思われた場合は、共有して転送してください。また、記事をフォローして、記事に対する認識と励ましを表明することもできます。
皆さんがプログラミングの道をどんどん進んでいけることを願っています。
推奨チュートリアル: 「JS チュートリアル 」
以上がJavaScript を使用して js インタープリターを作成するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。