- 原文地址:Evaluating JavaScript code via
import()
- 原文做者:Dr. Axel Rauschmayer
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:EmilyQiRabbit
- 校對者:quzhen12,weisiwu
import()
執行 JavaScript 代碼使用 import()
操做符,咱們能夠動態加載 ECMAScript 模塊。可是 import()
的應用不只於此,它還能夠做爲 eval()
的替代品,用來執行 JavaScript 代碼(這一點是最近 Andrea Giammarchi 向我指出的)。這篇博客將會解釋這是如何實現的。javascript
eval()
不支持 export
和 import
eval()
的一大缺陷是:它不支持例如 export
和 import
這樣的模塊語法。html
可是若是放棄 eval()
而改成使用 import()
,咱們就能夠執行帶有模塊的代碼,在後文你將能看到這是如何實現的。前端
將來,咱們也許能夠使用 Realms,它也許會是可以支持模塊的、更強大的下一代 eval()
。java
import()
執行簡單的代碼下面,咱們從使用 import()
來執行 console.log()
開始學習:android
const js = `console.log('Hello everyone!');`;
const encodedJs = encodeURIComponent(js);
const dataUri = 'data:text/javascript;charset=utf-8,'
+ encodedJs;
import(dataUri);
// 輸出:
// 'Hello everyone!'
複製代碼
這段代碼執行後發生了什麼?ios
data:
。URI 的剩餘部分中包含了全部資源的編碼,而不是指向資源自己的地址。這樣,數據 URI 就包含了一個完整的 ECMAScript 模塊 —— 它的 content 類型是 text/javascript
。注意:這段代碼只能在瀏覽器中運行。在 Node.js 環境中,import()
不支持數據 URI。git
由 import()
返回的 Promise 的完成態是一個模塊命名空間對象。這讓咱們能夠獲取到模塊的默認導出以及命名導出。在下面的例子中,咱們獲取得是默認導出:github
const js = `export default 'Returned value'`;
const dataUri = 'data:text/javascript;charset=utf-8,'
+ encodeURIComponent(js);
import(dataUri)
.then((namespaceObject) => {
assert.equal(namespaceObject.default, 'Returned value');
});
複製代碼
使用一個適當的方法 esm
(後文咱們會看到該方法是如何實現的),咱們能夠重寫上文的例子,並經過一個標記模版建立數據 URI:後端
const dataUri = esm`export default 'Returned value'`;
import(dataUri)
.then((namespaceObject) => {
assert.equal(namespaceObject.default, 'Returned value');
});
複製代碼
esm
的實現以下:瀏覽器
function esm(templateStrings, ...substitutions) {
let js = templateStrings.raw[0];
for (let i=0; i<substitutions.length; i++) {
js += substitutions[i] + templateStrings.raw[i+1];
}
return 'data:text/javascript;base64,' + btoa(js);
}
複製代碼
咱們把編碼方式從 charset=utf-8
切換爲 base64
,它們二者的對好比下:
'a' < 'b'
data:text/javascript;charset=utf-8,'a'%20%3C%20'b'
data:text/javascript;base64,J2EnIDwgJ2In
每種編碼方式都各有利弊:
charset=utf-8
(又稱百分號編碼)的優點:
base64
的優點:
btoa()
是一個用來將字符串編碼爲 base 64 代碼的全局工具函數。注意:
經過標記模版,咱們能夠嵌套數據 URI,並編碼引用了 m1
模塊的 m2
模塊:
const m1 = esm`export function f() { return 'Hello!' }`;
const m2 = esm`import {f} from '${m1}'; export default f()+f();`;
import(m2)
.then(ns => assert.equal(ns.default, 'Hello!Hello!'));
複製代碼
import()
的章節若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。