如何阻止 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 模块中,this
是 undefined
,而在 "script"
的情况下,这取决于环境,比如 window
CommonJS 代码中的浏览器脚本或 exports
。同样,"module"
文件自动严格,因此 Babel 将插入 "use strict";
.
在 Babel 7 中,如果你想避免这种行为,你需要告诉 Babel 你的文件是什么类型。最简单的选择是使用 "sourceType"
选项在你的 Babel 选项中设置 sourceType: "unambiguous"
,这实际上告诉 Babel 根据 import
的存在来猜测类型(脚本与模块)和 export
语句。主要的缺点是拥有一个不使用 import
或 export
的 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 模块中,this
是 undefined
并且文件都是严格的,而在 "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 打包的其他库造成了严重破坏。
编辑:这与粗箭头无关。它也不是将 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 模块中,this
是 undefined
,而在 "script"
的情况下,这取决于环境,比如 window
CommonJS 代码中的浏览器脚本或 exports
。同样,"module"
文件自动严格,因此 Babel 将插入 "use strict";
.
在 Babel 7 中,如果你想避免这种行为,你需要告诉 Babel 你的文件是什么类型。最简单的选择是使用 "sourceType"
选项在你的 Babel 选项中设置 sourceType: "unambiguous"
,这实际上告诉 Babel 根据 import
的存在来猜测类型(脚本与模块)和 export
语句。主要的缺点是拥有一个不使用 import
或 export
的 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 模块中,this
是 undefined
并且文件都是严格的,而在 "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 打包的其他库造成了严重破坏。