- 原文地址: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、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。