TL;DR
这是因为使用import 导入不同于require。当您使用语法import X from "Y" 导入模块时,会自动导入默认导出,因为该语法旨在按规范导入默认导出。但是,当您require 时,默认导出不会像您期望的那样自动导入。您必须添加.default 才能使用require 获得默认导出,例如:require("./foo").default。
Babel 转译
看一下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();
您会看到默认导出作为名为@987654339@ 的属性附加到exports 对象,就像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"] 将ES5 中的module.exports 分配给exports["default"]。1
import 和 require 之间的区别
对于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 只需 requires 模块。然后,它在模块上调用_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.exports和exports只是指同一个对象,见this answer。 module.exports 保存从模块导出的数据。 module.exports = x 成功导出x 作为默认值并且不需要require 上的额外.default 的原因是因为您将module.exports 分配给一件事。因为module.exports 保存了导入的数据,所以require("module") 导入module.exports 的任何内容,即x。如果module.exports 是3,那么require("module") 就是3。如果module.exports 是像{ blah: "foo" } 这样的对象,那么require("module") 就是{ blah: "foo" }。默认情况下,module 和 module.exports 是对象。
另一方面,exports.default 导出一个对象(与module.exports 引用相同的对象),该对象的default 属性包含默认导出。您可能希望使用exports = x 将x 导出为默认值,但由于exports 被分配了对module.exports 的引用,这将破坏引用并且exports 将不再指向module.exports。