导入与需求与巴贝尔节点
我想要在一个文件中导入一个类:
"use strict"; import models from "../model"; class Foo { bar() { } } export default new Foo();
它使用导入时,如:
import Foo from "./foo"; console.log(Foo.bar); // [Function bar]
问题是,使用require来给我定义:
var Foo = require("./foo"); console.log(Foo.bar); // undefined
而Foovariables似乎是一个空的类。 为什么? 这是怎么回事?
TL; DR
这是因为导入import
不同于require
。 import X from "Y"
语法为import X from "Y"
的模块时,会自动导入默认导出,因为语法是为了按规范导入默认导出。 但是,如果require
,默认导出不会像您期望的那样自动导入。 您必须添加.default
以获取默认导出,如require("./foo").default
。
Babel Transpilation
看看巴贝尔如何编译一些示例代码:
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();
您将看到默认导出作为名为default
的属性附加到了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
属性来访问您的实例。
你可能会觉得这有点笨重,其他的也可以。 这就是为什么有一个插件来摆脱额外的.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只require
模块。 然后,它调用模块上的_interopRequireDefault
。 使用obj && obj.__esModule
进行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代码,所以没有什么是transpiled。 因此,使用.default
永远不会添加到Foo
。 因此,默认导出不被检索。
笔记
1应该注意的是module.exports
和exports
只是指向同一个对象,看到这个答案 。 module.exports
保存从模块导出的数据。 之所以module.exports = x
成功地将x
导出为默认值,并且不需要额外的.default
on require
,因为您将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
是对象。
另一方面, module.exports
用一个保存默认导出的default
属性导出一个对象(引用与module.exports
相同的对象)。 您可能需要执行exports = x
来将x
导出为默认值,但是由于exports
被分配了对module.exports
的引用,因此将会中断引用, exports
将不再指向module.exports
。