导入与在节点中使用Babel的要求

时间:2017-02-26 23:46:02

标签: javascript node.js ecmascript-6 babeljs

我想在一个文件中导入一个类:

"use strict";
import models from "../model";
class Foo {
    bar() {
    }
}
export default new Foo();

当我使用import时,它可以工作,例如:

import Foo from "./foo";
console.log(Foo.bar); // [Function bar]

问题是,使用require执行此操作会给我一些未定义的内容:

var Foo = require("./foo");
console.log(Foo.bar); // undefined

并且Foo变量似乎是一个空类。为什么会这样?发生了什么事?

1 个答案:

答案 0 :(得分:9)

TL; DR

这是因为import导入与require不同。导入语法为import X from "Y"的模块时,会自动导入默认导出,因为语法是按规范导入默认导出。但是,当您require时,默认导出会自动导入,就像您期望的那样。您必须添加.default才能获得require的默认导出,例如:require("./foo").default

Babel Transpilation

看看Babel transpiles一些示例代码:

export { x }

变为:

"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.x = x;

这是有道理的,因为x只是正常导出。然后你会继续做:

require("module").x;

接收x。同样,请尝试以下方法:

export default new Foo();

那变为:

"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = new Foo();

您将看到默认导出作为名为exports的属性附加到default对象,就像导出x属性x一样。这意味着,要使用require获取默认导出,您需要执行以下操作:

require("module").default;

现在解释它undefined的原因。在该行:

var Foo = require("./foo");

Foo这里实际上只是一个default属性的对象:

{
    default: //Whatever was exported as default
}

因此,尝试执行Foo.bar会产生undefined,因为没有bar属性。您需要访问default属性才能访问您的实例。

你可能认为这有点笨拙,而其他人也这么做。这就是there's a plugin摆脱额外.default的必要性的原因。该插件会module.exports = exports["default"]module.exports从ES5分配到exports["default"] 1

importrequire

之间的差异

对于import语法,Babel执行以下转换:

import Foo from "./foo";
Foo.bar();

变为:

"use strict";

var _foo = require("./foo");

var _foo2 = _interopRequireDefault(_foo);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

_foo2.default.bar();

要逐行分解,Babel只需require个模块。然后,它在模块上调用_interopRequireDefault。使用obj && obj.__esModule进行检查以确保模块实际导出任何内容,并使用ES2015 / ES6语法导出模块。如果是,则按原样返回模块,否则返回{ default: obj }。这是为了确保ES5中的module.exports = x与ES2015 / ES6中的export default x相同。您会注意到,对于默认导入语法,Babel会自动添加.default以检索默认导出。

但是,相应的代码包含require

var Foo = require("./foo");
Foo.bar();

是完全有效的ES5代码,因此没有任何内容被编译。因此,.default在使用时永远不会添加到Foo。因此,不会检索默认导出。

注释

1 应该注意module.exportsexports只是引用同一个对象,请参阅this answermodule.exports保存从模块导出的数据。 module.exports = x成功导出x作为默认值并且不需要.default上的额外require的原因是因为您要将module.exports分配给一个module.exports单身的东西。由于require("module")包含导入的数据,module.exports会导入xmodule.exportsrequire("module")。如果module.exports为3,则{ blah: "foo" }为3.如果require("module"){ blah: "foo" }之类的对象,则module将为module.exports。默认情况下,exports.defaultmodule.exports是对象。

另一方面,default使用保存默认导出的exports = x属性导出对象(指向与x相同的对象)。您可能希望exports导出module.exports作为默认值,但由于exports被分配了对module.exports的引用,这将打破引用,div将不再指向[JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public IEnumerable<Season> seasons { get; set; }