如何阻止 babel 将 'this' 转译为 'undefined'(并插入 "use strict")

How to stop babel from transpiling 'this' to 'undefined' (and inserting "use strict")

编辑:这与粗箭头无关。它也不是将 this 传递给 IIFE。这是一个与编译器相关的问题。

所以我为我正在开发的一个小应用程序创建了一个简单的发布-订阅。我用 ES6 编写它以使用 spread/rest 并省去一些麻烦。我用 npm 和 gulp 设置它来转译它,但这让我发疯。

我把它变成了一个浏览器库,但意识到它可以在任何地方使用,所以我决定让它与 Commonjs 和 AMD 兼容。

这是我的代码的精简版:

(function(root, factory) {
 if(typeof define === 'function' && define.amd) {
    define([], function() {
        return (root.simplePubSub = factory())
    });
  } else if(typeof module === 'object' && module.exports) {
    module.exports = (root.simplePubSub = factory())
  } else {
    root.simplePubSub = root.SPS = factory()
  }
}(this, function() {
 // return SimplePubSub
});

但无论我尝试什么(例如将 this 设为变量并传递它),它都会将其设置为 undefined.

}(undefined, function() {

这可能与 Babel 不知道 this 会是什么并将其转译有关,但我可以采用其他方法吗?

UPDATE:传递 }((window || module || {}), function() { 而不是 this 似乎有效。不过我不确定这是最好的方法。

对于 Babel >= 7.x

ES6代码有两种处理方式:

  • "script" - 当您通过 <script> 或任何其他标准 ES5 加载文件的方式加载文件时
  • "module" - 当文件作为 ES6 模块处理时

在 Babel 7.x 中,文件默认被解析为 "module"。给你带来麻烦的是,在 ES6 模块中,thisundefined,而在 "script" 的情况下,这取决于环境,比如 window CommonJS 代码中的浏览器脚本或 exports。同样,"module" 文件自动严格,因此 Babel 将插入 "use strict";.

在 Babel 7 中,如果你想避免这种行为,你需要告诉 Babel 你的文件是什么类型。最简单的选择是使用 "sourceType" 选项在你的 Babel 选项中设置 sourceType: "unambiguous",这实际上告诉 Babel 根据 import 的存在来猜测类型(脚本与模块)和 export 语句。主要的缺点是拥有一个不使用 importexport 的 ES6 模块在技术上是可以的,并且这些模块会被错误地视为脚本。另一方面,这真的不那么常见。

或者,您可以使用 Babel 7 的 "overrides" 选项将特定文件设置为脚本,例如

overrides: [{
  test: "./vendor/something.umd.js",
  sourceType: "script",
}],

这两种方法都允许 Babel 知道某些文件是 script 类型,因此不应该将 this 转换为 undefined

对于 Babel < 7.x

ES6代码有两种处理方式:

  • "script" - 当您通过 <script> 或任何其他标准 ES5 加载文件的方式加载文件时
  • "module" - 当文件作为 ES6 模块处理时

当使用 Babel 6 和 babel-preset-es2015(或 Babel 5)时,Babel 默认假定它处理的文件是 ES6 模块。给你带来麻烦的是,在 ES6 模块中,thisundefined 并且文件都是严格的,而在 "script" 的情况下,this 根据环境,例如浏览器脚本中的 window 或 CommonJS 代码中的 exports

如果您使用的是 Babel,最简单的选择是在不使用 UMD 包装器的情况下编写代码,然后使用 Browserify 之类的工具捆绑您的文件,以自动为您添加 UMD 包装器。 Babel 还提供了一个babel-plugin-transform-es2015-modules-umd。两者都旨在简化,因此如果您想要定制的 UMD 方法,它们可能不适合您。

或者,您需要明确列出 babel-preset-es2015 中的所有 Babel 插件,确保排除 module-processing babel-plugin-transform-es2015-modules-commonjs 插件。请注意,这也会停止自动添加 use strict,因为这也是 ES6 规范的一部分,您可能希望添加回 babel-plugin-transform-strict-mode 以自动保持代码严格。

babel-core@6.13 开始,预设可以选择,所以你也可以

{
  "presets": [
    [ "es2015", { "modules": false } ]
  ]
}

在您的 Babel 配置 (.babelrc) 中使用 babel-preset-es2015 并禁用模块处理。

"es2015" 预设默认将 Babel 输出包装在 commonJs 包装器中。使用 "babel-preset-es2015-script"(你必须先 npm install --save babel-preset-es2015-script)输出 "script"(无模块)。这对我使用 Babel 打包的其他库造成了严重破坏。

预设:https://www.npmjs.com/package/babel-preset-es2015-script