【译】使用“import”执行JavaScript代码

在这里插入图片描述
使用 import() 操作符,我们可以动态加载 ECMAScript 模块。但是 import() 的应用不仅于此,它还可以作为 eval() 的替代品,用来执行 JavaScript 代码(这一点是最近 Andrea Giammarchi 向我指出的)。这篇博客将会解释这是如何实现的。

eval() 不支持 export 和 import

eval() 的一大缺陷是:它不支持例如 export 和 import 这样的模块语法。
但是如果放弃 eval() 而改为使用 import(),我们就可以执行带有模块的代码,在后文你将能看到这是如何实现的。
未来,我们也许可以使用 Realms,它也许会是能够支持模块的、更强大的下一代 eval()。

使用 import() 执行简单的代码

下面,我们从使用 import() 来执行 console.log() 开始学习:

const js = `console.log('Hello everyone!');`;
const encodedJs = encodeURIComponent(js);
const dataUri = 'data:text/javascript;charset=utf-8,'
  + encodedJs;
import(dataUri);

// 输出:
// 'Hello everyone!'

这段代码执行后发生了什么?

  • 首先,我们创建了所谓的 数据 URI。这种类型的 URI 协议是 data:。URI 的剩余部分中包含了所有资源的编码,而不是指向资源本身的地址。这样,数据 URI 就包含了一个完整的 ECMAScript 模块 —— 它的 content 类型是 text/javascript。

  • 然后我们动态引入模块,于是代码被执行。

注意:这段代码只能在浏览器中运行。在 Node.js 环境中,import() 不支持数据 URI。

获取被执行模块的导出

使用一个适当的方法 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’
  • 第一个数据 URI:data:text/javascript;charset=utf-8,‘a’%20%3C%20’b’
  • 第二个数据 URI:data:text/javascript;base64,J2EnIDwgJ2In

每种编码方式都各有利弊:

  • charset=utf-8(又称百分号编码)的优势: 大部分源码仍具有可读性
  • base64 的优势:URI 更精短。更易嵌套(后文我们会看到),因为它不包含任何如撇号这样的特殊字符。

btoa() 是一个用来将字符串编码为 base 64 代码的全局工具函数。注意:

  1. 在 Node.js 环境下不可用
  2. 仅对码点值在 0 至 255 范围内的 Unicode 字符有效。

执行引用了其他模块的模块

通过标记模版,我们可以嵌套数据 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!'));

扩展阅读

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值