如何在 Javascript 中检查脚本是否作为 ES6 模块运行(以便它可以“导出”)?

Кон*_*Ван 5 javascript es6-modules

我想制作一个 Javascript 文件

  • exports 它的内容(例如一个类)如果可以export(例如它已经加载了<script type="module">
  • 否则,将其内容分配给全局变量,例如windowand global

例如,让我们假设这样一个文件print.js.

案例A

人们可以像这样使用它:

<script type="module">
    import print_things from "./print.js";
    print_things("Javascript innovation");
</script>
Run Code Online (Sandbox Code Playgroud)

案例B

或者,

<script src="./print.js"></script>
<script>
    print_things("Hmmmmmmm.");
</script>
Run Code Online (Sandbox Code Playgroud)

目前, usingexport使脚本在Case B : 中引发错误Uncaught SyntaxError: Unexpected token export。因此,它必须知道export在其运行的环境中是否可用,以支持这两个用例。我该怎么做呢?

12M*_*e21 5

注意:您可能不应该在现实世界中使用它,但它完全有效的并且完全符合您的要求。)
这是您的实现print.js

function print_things(msg) {
   console.log(msg)
}
if(0)typeof await/2//2; export default print_things
Run Code Online (Sandbox Code Playgroud)

<script type=module>
   // (renamed to avoid name collision)
   import print_things2 from "https://12Me21.github.io/external/print.js"
   print_things2("Javascript innovation")
</script>

<script src="https://12Me21.github.io/external/print.js"></script>
<script>
   print_things("Hmmmmmmm.")
</script>
Run Code Online (Sandbox Code Playgroud)
此语法将从非模块脚本中“隐藏”导出语句,因为await/2//2; ...根据上下文进行不同的解析:

  • 在模块异步函数中:(
    await运算符)/2/(正则表达式)/(除法)2(数字)
  • 在普通脚本中:(
    await变量)/(除法)2(数字)//2 ... 注释

当它被解析为注释时,该行的其余部分将被忽略。因此,该export语句仅对模块脚本可见。

以下是规范的相关部分: 15.8 Async Function Definitions > Syntax > AwaitExpression > Note 1

兼容性

作为非模块脚本,它应该在任何浏览器(甚至是 Internet Explorer 等的旧版本)中工作,并且在"use strict"启用时仍然有效

但是,将其作为模块加载需要支持“顶级等待”,该支持是在模块本身几年后添加的(〜2021年与〜2018年),因此请记住这一点。
(它也适用于 Nodejs,无论哪种模式)

我在自己编写的库中使用了这个技巧,并且它在多个环境中运行良好几个月。然而,它给外部工具(框架、编译器、压缩器等)带来了一些问题。

  • 我现在有一个可能更好的选择,它可以在node.js中使用:`if(0)+typeof wait/2//2; 导出...`(或只是`0&amp;&amp;await/2//2;导出...`) (2认同)

xav*_*did 1

查看UMD(通用模块定义)。也就是说,这个例子

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['exports', 'b'], function (exports, b) {
            factory((root.commonJsStrictGlobal = exports), b);
        });
    } else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
        // CommonJS
        factory(exports, require('b'));
    } else {
        // Browser globals
        factory((root.commonJsStrictGlobal = {}), root.b);
    }
}(typeof self !== 'undefined' ? self : this, function (exports, b) {
    // Use b in some fashion.

    // attach properties to the exports object to define
    // the exported module properties.
    exports.action = function () {};
}));
Run Code Online (Sandbox Code Playgroud)