在声明之前导出对象和类使它们未定义

时间:2016-01-05 05:29:24

标签: ecmascript-6 babeljs

我尝试从Mozilla Hacks导出列表副标题)重复示例:

//export.js
export {detectCats, Kittydar};
function detectCats() {}
class Kittydar {}

//import.js
import {detectCats, Kittydar} from "./export.js";
console.log(detectCats); // function detectCats() {}
console.log(Kittydar); // undefined

糟糕:Kittydar未定义(顺便说一下,问题与简单的Object相同)。

但如果我在export声明之后放Kittydar就可以了:

//export.js
class Kittydar {}
export {Kittydar};

//import.js
import {Kittydar} from "./export.js";
console.log(Kittydar); // function Kittydar() {_classCallCheck(this, Kittydar);}

这是文章中的拼写错误吗?

我使用babel将其与browserify捆绑在一起。然后我将输出包包含在通常的.html文件中(带有<script>标记)。

1 个答案:

答案 0 :(得分:5)

标准很难遵循,但文章是正确的。此代码适用于es6draft和SpiderMonkey shell:函数和类都在console.log调用运行时初始化。

以下是它应该如何工作的细节:

  • JS引擎解析import.js。它会看到import声明,因此它会加载export.js并对其进行解析。

  • 在实际运行任何代码之前,系统会创建两个模块范围,并使用每个模块中声明的所有顶级绑定填充它们。 (规范称为ModuleDeclarationInstantiation。)在export.js中创建Kittydar绑定,但它现在尚未初始化。

    在import.js中,创建了Kittydar 导入绑定。它是export.js中Kittydar绑定的别名。

  • export.js运行。该类已创建。 Kittydar已初始化。

  • import.js运行。两个console.log()调用都可以正常工作。

Babel对ES6模块的实施是非标准的。

我认为这是故意的。 Babel旨在将ES6模块编译成ES5代码,该代码可与您选择的现有模块系统配合使用:您可以将其吐出AMD模块,UMD,CommonJS等。因此,如果您要求AMD输出,您的代码可能是ES6模块,但ES5输出是一个AMD模块,它的行为就像一个AMD模块。

Babel可能更符合标准,同时仍能很好地与各种模块系统集成,但存在权衡。