亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > JS > 正文

用 js 寫一個 js 解釋器過程詳解

2024-05-06 16:53:56
字體:
來源:轉載
供稿:網友

用 js 來 編譯 js 看起來是個高大上的東西,實際原理其實很簡單,無非就是利用 js 對象屬性可以用字符串表示 這個特性來實現的黑魔法罷了。

之所以看起來那么 深奧, 大概是由于網上現有的教程,都是動不動就先來個 babylon / @babel/parser 先讓大家看個一大串的 AST, 然后再貼出一大串的代碼,

直接遞歸 AST 處理所有類型的節點. 最后成功的把我這樣的新手就被嚇跑了。

那么今天我寫這篇的目的,就是給大家一個淺顯易懂,連剛學 js 的人都能看懂的 js2js 教程。

先來看一下效果

js,js解釋器

一個最簡單的解釋器

上面有提到,js 有個特性是 對象屬性可以用字符串表示,如 console.log 等價于 console['log'], 辣么根據這個特性,我們可以寫出一個兼容性極差,極其簡陋的雛形

 function callFunction(fun, arg) { this[fun](arg); } callFunction('alert', 'hello world'); // 如果你是在瀏覽器環境的話,應該會彈出一個彈窗

既然是簡易版的,肯定是問題一大堆,js 里面得語法不僅僅是函數調用,我們看看賦值是如何用黑魔法實現的

 function declareVarible(key, value) { this[key] = value; } declareVarible.call(window, 'foo', 'bar'); // window.foo = 'bar'

Tips: const 可以利用 Object.defineProperty 實現;

如果上面的代碼能看懂,說明你已經懂得了 js 解釋器 的基本原理了,看不懂那只好怪我咯。

稍微加強一下

可以看出,上面為了方便, 我們把函數調用寫成了 callFunction('alert', 'hello world'); 但是著看起來一點都不像是 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 里面的所有屬性名為 type 的數據

  • ExpressionStatement
  • CallExpression
  • Identifier
  • Literal

一共有 4 種類型, 那么接下來我們把這 4 種節點分別解析, 從最簡單的開始

Literal

{ "type": "Literal", "value": "hello world!",}

針對 Literal 的內容, 我們需要的只有一個 value 屬性, 直接返回即可.

if(node.type === 'Literal') { return node.value;}

是不是很簡單?

Identifier

{ "type": "Identifier", "name": "alert"},

Identifier 同樣也很簡單, 它代表的就是我們已經存在的一個變量, 變量名是node.name, 既然是已經存在的變量, 那么它的值是什么呢?

if(node.type === 'Identifier') { return { name: node.name, value:this[node.name] };}

上面的 alert 我們從 node.name 里面拿到的是一個字符, 通過 this['xxxxx'] 可以訪問到當前作用域(這里是 window)里面的這個標識符(Identifier)

ExpressionStatement

{ "type": "ExpressionStatement", "expression": {...}}

這個其實也是超簡單, 沒有什么實質性的內容, 真正的內容都在 expression 屬性里,所以可以直接返回 expression 的內容

if(node.type === 'ExpressionStatement') { return parseAstNode(node.expression);}

CallExpression

CallExpression 按字面的意思理解就是 函數調用表達式,這個稍微麻煩一點點

{ "type": "CallExpression", "callee": {...}, "arguments": [...]}

CallExpression 里面的有 2 個我們需要的字段:

callee 是 函數的引用, 里面的內容是一個 Identifier, 可以用上面的方法處理.

arguments 里面的內容是調用時傳的參數數組, 我們目前需要處理的是一個 Literal, 同樣上面已經有處理方法了.

說到這里,相信你已經知道怎么做了

if(node.type === 'CallExpression') { // 函數 const callee = 調用 Identifier 處理器 // 參數 const args = node.arguments.map(arg => { return 調用 Literal 處理器 }); callee(...args);}

代碼

這里有一份簡單的實現, 可以跑通上面的流程, 但也僅僅可以跑通上面而已, 其他的特性都還沒實現。

https://github.com/noahlam/practice-truth/tree/master/js2js

其他實現方式

除了上面我介紹得這種最繁瑣得方式外,其實 js 還有好幾種可以直接執行字符串代碼得方式

1.插入 script DOM

 const script = document.createElement("script"); script.innerText = 'alert("hello world!")'; document.body.appendChild(script);

2.eval

 eval('alert("hello world!")')

3.new Function

 new Function('alert("hello world")')();

4.setTimeout 家族

setTimeout('console.log("hello world")');

不過這些在小程序里面都被無情得封殺了...

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
97色在线观看免费视频| 日韩av快播网址| 日韩免费av在线| 日韩免费观看高清| 久久精品亚洲精品| 精品人伦一区二区三区蜜桃免费| 日韩精品久久久久久久玫瑰园| 国产精品99久久久久久白浆小说| 欧美日本在线视频中文字字幕| 亚洲性视频网站| 一个人www欧美| 久久久国产一区二区三区| 国产精品福利在线观看网址| 午夜精品久久久久久久久久久久久| 成人在线小视频| 欧美日韩国产二区| 国产精品亚洲片夜色在线| 国产视频精品va久久久久久| 欧美精品aaa| 这里只有精品在线播放| 视频直播国产精品| 欧美日韩国产一区二区三区| 色青青草原桃花久久综合| 亚洲男人天堂网| 国产精品第七十二页| 国产精品极品美女粉嫩高清在线| 国产精品久久久久久影视| 国产精品久久久亚洲| 欧美限制级电影在线观看| 国产精品久久综合av爱欲tv| 欧美一区二区三区免费观看| 国产精品激情自拍| 91牛牛免费视频| 俺去啦;欧美日韩| 欧美视频免费在线观看| 国产日韩欧美视频| 亚洲国产成人一区| 亚洲国产成人精品女人久久久| 粉嫩老牛aⅴ一区二区三区| 欧美激情视频在线| 91美女片黄在线观| 国产精品视频在线观看| 久久99久久99精品中文字幕| 亚州av一区二区| 国产精品亚洲视频在线观看| 黑人巨大精品欧美一区二区三区| 精品自在线视频| 国内精品免费午夜毛片| 久久免费精品日本久久中文字幕| 欧美福利视频在线| 成人a在线观看| 色妞在线综合亚洲欧美| 国产在线视频欧美| 久久久久www| 欧美电影免费在线观看| 久久免费精品视频| 国产91在线播放九色快色| 岛国av一区二区| 国产精品久久中文| 欧美国产在线视频| 色噜噜狠狠色综合网图区| 2018中文字幕一区二区三区| 成人中文字幕在线观看| 国产成人综合一区二区三区| 亚洲精品一区在线观看香蕉| 一二美女精品欧洲| 欧美日韩午夜激情| 成人久久一区二区| 精品偷拍一区二区三区在线看| 亚洲欧洲国产一区| 亚洲男人天堂网| 亚洲人成毛片在线播放| 日韩最新中文字幕电影免费看| 国产69精品99久久久久久宅男| 久久久视频免费观看| 亚洲无亚洲人成网站77777| 精品国产电影一区| 国产精品久久在线观看| 日韩欧美一区二区三区| 国产福利视频一区| 日本免费一区二区三区视频观看| 综合网日日天干夜夜久久| 热草久综合在线| 久久精品色欧美aⅴ一区二区| 久久精品久久久久久| 中文字幕v亚洲ⅴv天堂| 亚洲精品wwwww| 欧美美女18p| 5252色成人免费视频| yellow中文字幕久久| 自拍偷拍亚洲一区| 久久久久久九九九| 综合网日日天干夜夜久久| 国产精品普通话| 日韩精品在线播放| 国产精品夜色7777狼人| 57pao国产精品一区| 欧美激情视频三区| 伊人久久精品视频| 亚洲国产97在线精品一区| 国模叶桐国产精品一区| 日韩精品久久久久久福利| 欧美中文在线观看| 久久精品成人欧美大片古装| 在线电影中文日韩| 精品久久久999| 亚洲在线一区二区| 成人黄色激情网| 国产精品老牛影院在线观看| 中文字幕日韩有码| 欧美性猛交xxxx黑人猛交| 久久视频在线播放| 日韩精品中文字幕在线观看| 亚洲日本欧美日韩高观看| 国产成人aa精品一区在线播放| 日韩欧美极品在线观看| 国模gogo一区二区大胆私拍| 国产精品99免视看9| 精品一区二区三区四区在线| 狠狠久久五月精品中文字幕| 欧美日韩ab片| 久久人91精品久久久久久不卡| 欧美日韩在线免费| 欧美日韩国产色| 亚洲欧美福利视频| 久久午夜a级毛片| 亚州国产精品久久久| 国产亚洲精品一区二区| 欧美激情综合亚洲一二区| 久久伊人精品视频| 伊人久久免费视频| 97成人精品区在线播放| 成人在线视频网| 亚洲第一综合天堂另类专| 国产欧美一区二区三区在线| 欧美激情免费看| 亚洲第一免费播放区| 欧美视频在线观看免费网址| 欧日韩在线观看| 欧美性猛交xxxxx免费看| 亚洲欧美日韩国产精品| 奇门遁甲1982国语版免费观看高清| 亚洲18私人小影院| 亚洲精品午夜精品| 最近2019中文字幕在线高清| 色悠悠久久久久| 97av在线视频免费播放| 国产精品黄色影片导航在线观看| 亚洲成人激情小说| 九九精品在线播放| 精品久久久在线观看| 国产精品久久久久久中文字| 2020欧美日韩在线视频| 久久久久免费视频| 国产视频自拍一区| 97精品视频在线观看| 清纯唯美亚洲激情| 日韩69视频在线观看| 国产激情综合五月久久| 91国偷自产一区二区三区的观看方式| 亚洲黄页视频免费观看| 91精品国产自产在线老师啪| 在线观看视频99| 欧美视频在线免费看|