IIFE 和 ES6 模块的区别是什么?

3

我有一个库,基本上是一个IIFE(立即执行函数表达式),它设置了一个全局变量,客户端应该操作这个变量。因此,在module.js中,我有以下内容:

window.myModule = (function(){
    ...

    return {
        foo: foo,
        bar: bar
    }
})();

我希望让它兼容ES6模块,这样我就可以做到:
import * as theModule from 'module.js';

同样也包括
<script src="module.js"></script>

如何实现这一点?我记得有些库是这样的(甚至兼容AMD),但我甚至不知道该搜索什么。


你能分享IIFE的签名吗? - seebiscuit
1
通用模块定义 (UMD) - Patrick Roberts
@seebiscuit 完成。 - user4052054
2个回答

2
ES6模块,在我看来,受到了IIFE价值的启发,封装是其中一个重要的好处。因此,重构IIFE可能很简单。
首先,您可以删除IIFE包装器(您不必这样做,但没有保留它的好处,而且您可能需要小心,因为传递的参数作用域可能会有所不同)。
如果您知道该库仅适用于浏览器,并且想要保持向后兼容性,则可以将root变量替换为window
下一个挑战是识别公共API并导出它。因此,假设原始API看起来像这样:
root.MyLib.prototype.somePublicFn = function () {...}

您可以这样导出该函数:

像这样

。最初的回答已经涵盖了您需要的信息。
export let somePublicFn = function () {...}

And, when you do

import * as libFns from 'myLib'

libFns将充当一种命名空间,使您能够执行以下操作:

最初的回答:

libFns.somePublicFn(...)

在导入模块中。就像我上面提到的那样,如果你想要将这些导出项也在全局范围内可用,你需要手动编写代码,例如:
"最初的回答"

在导入模块中。

并且,如我之前所述,如果您想要将这些导出项在全局范围内也可用,您需要手动编写代码,例如:

const api = {
  somePublicFn
  ...
}
root.MyLib.prototype = Object.assign(root.MyLib.prototype, api)

0

你需要区分你编写的代码和提供给他人使用的代码:后者是一个工具问题。

编写ES模块,然后使用类似this的东西来为你的用户提供一些可以通过他们选择的方法轻松消费的东西:commonJS、AMD、全局等等,你只需要进行构建流程步骤即可。

移除IIFE包装器并导出你分配的内容。

关于webpack的注意事项:

Webpack使用一种... ES2015-ish语法来处理模块,但实际上并不适用于例如<script type="module">。由于webpack几乎成为了行业标准,我不能不提及它。不幸的是,它与上述设置并不完全兼容。据我所知,这仍然是一个未解决的问题。


我不想使用另一个构建步骤。我记得有一次检查过一个以 if 开头的模块,检查环境是否支持 ES6 模块,但我不记得接下来该怎么做了。 - user4052054
@user4052054,那是不可能的。ES 6模块是静态链接的。在条件语句中(或者除了顶层之外的任何地方)使用import或export语句都是语法错误。有一个基于Promise的动态导入提案,但尚未标准化。要么进行构建步骤,要么继续编写IIFEs。 - Jared Smith

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接