【问题标题】:Compiling ES6 arrow functions to Es5 using Babel.js使用 Babel.js 将 ES6 箭头函数编译为 Es5
【发布时间】:2015-08-22 12:43:48
【问题描述】:



在查看 Mozilla 文档中的 ES6 箭头函数文档时,我了解到箭头函数应用严格模式的所有规则,除了 link 中描述的规则之外

  var f = () => { 'use strict'; return this};
    var g = function () { 'use strict'; return this;}

    console.log(f()); //prints Window
    console.log(g()); // prints undefined

    //we can test this in firefox!

但是,Babel.js 将箭头函数代码转换为 ES5 代码,返回 undefined 而不是 Window(demo link)

"use strict";

setTimeout(function () {
  return undefined;
}, 100);

所以,上面的 sn-p 是 Babel.js 的输出。不能是下面的输出吗?

"use strict";

setTimeout(function () {
  return this;
}.bind(Window), 100);

如果我正在编写 ES6,我希望 Window 而不是 undefined
这是一个错误吗?
或者,我误解了什么?

【问题讨论】:

  • Babel 将所有内容置于严格模式。 undefined 看起来正确。
  • @elclanrs 从 ES5 的角度来看是正确的,因为代码被转译为 ES5,但在 ES6 中的箭头函数的情况下,它应该是 window
  • @dfsq 为什么应该是窗口?它将从未定义的封装对象继承this;不是全球的。还是我想错了?

标签: javascript scope ecmascript-6 babeljs lexical-scope


【解决方案1】:

您在原则上是正确的,如MDN 所述。但是,Babel 总是将 'use strict' 放在根范围内。实际上你编译了以下内容:

'use strict';
var f = () => { 'use strict'; return this};

在这种情况下,确实适用严格的规则。请参阅编译示例here。 Babel 甚至优化掉了*的this,因为它保证是undefined

【讨论】:

  • 这就是我所怀疑的......我希望输出是Window并编写我的代码......那么,它怎么可能有效?
  • @Navaneeth 当'use strict' 是脚本中的第一条语句时,全局this 对象变为未定义(see here)。这也适用于从全局范围继承的其他块。尝试例如(function() { console.log(this); }) ()(function() { 'use strict'; console.log(this); }) ()。由于 Babel 完全在严格模式下运行,它的编译器正确地假定 this 在全局范围内是未定义的。如果您想访问window 对象,只需显式执行即可。
【解决方案2】:

tl;dr: Babel 假设每个文件都是一个模块。默认情况下,模块是 strict,它们的 this 值为 undefined


这在Babel FAQ:

Babel 假设所有输入代码都是一个 ES2015 模块。 ES2015 模块是隐式严格模式,所以这意味着* this 不是浏览器中的 window 也不是节点中的 exports

如果您不想要这种行为,那么您可以选择禁用严格的转换器:

$ babel --blacklist strict script.js

require("babel").transform("code", { blacklist: ["strict"] });

请注意:如果您这样做,则表示您愿意偏离规范,这可能会导致未来的互操作问题。

请参阅strict transformer docs 了解更多信息。

【讨论】: