在Node.js和ES6中的module.exports vs. export default
Node的 module.exports
和ES6的导出默认值
之间有什么区别?我试图找出当我尝试在Node.js 6.2.2中 export default
时,为什么我得到__不是构造函数错误。
What is the difference between Node's module.exports
and ES6's export default
? I'm trying to figure out why I get the "__ is not a constructor" error when I try to export default
in Node.js 6.2.2.
'use strict'
class SlimShady {
constructor(options) {
this._options = options
}
sayName() {
return 'My name is Slim Shady.'
}
}
// This works
module.exports = SlimShady
什么不工作
What doesn't work
'use strict'
class SlimShady {
constructor(options) {
this._options = options
}
sayName() {
return 'My name is Slim Shady.'
}
}
// This will cause the "SlimShady is not a constructor" error
// if in another file I try `let marshall = new SlimShady()`
export default SlimShady
问题在于
- 如何在CommonJS中模拟ES6模块
- 如何导入模块
在写这篇文章的时候,没有环境支持ES6模块本身。在Node.js中使用它们时,您需要使用像Babel这样的模块将模块转换为CommonJS。但是这究竟是怎么发生的?
At the time of writing this, no environment supports ES6 modules natively. When using them in Node.js you need to use something like Babel to convert the modules to CommonJS. But how exactly does that happen?
许多人认为 module.exports = ...
相当于 export default ... 和 exports.foo ...
相当于 export const foo = ...
。这不是真的,或者至少不是Babel这样做。
Many people consider module.exports = ...
to be equivalent to export default ...
and exports.foo ...
to be equivalent to export const foo = ...
. That's not quite true though, or at least not how Babel does it.
ES6 默认
出口实际上也是命名导出,除了默认
是一个保留名称,并且它有特殊的语法支持。让我们看看Babel如何编译命名和默认导出:
ES6 default
exports are actually also named exports, except that default
is a "reserved" name and there is special syntax support for it. Lets have a look how Babel compiles named and default exports:
// input
export const foo = 42;
export default 21;
// output
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var foo = exports.foo = 42;
exports.default = 21;
这里我们可以看到默认导出成为导出
对象,就像 foo
。
Here we can see that the default export becomes a property on the exports
object, just like foo
.
我们可以通过两种方式导入模块:使用CommonJS或使用ES6 import
语法。
We can import the module in two ways: Either using CommonJS or using ES6 import
syntax.
您的问题:我相信您正在执行以下操作:
Your issue: I believe you are doing something like:
var bar = require('./input');
new bar();
期望 bar
被赋值默认导出。但是我们可以在上面的示例中看到,默认导出被分配给默认值
属性!
expecting that bar
is assigned the value of the default export. But as we can see in the example above, the default export is assigned to the default
property!
所以在订单访问我们实际必须做的默认导出
So in order to access the default export we actually have to do
var bar = require('./input').default;
如果我们使用ES6模块语法,即
If we use ES6 module syntax, namely
import bar from './input';
console.log(bar);
Babel将其转换为
Babel will transform it to
'use strict';
var _input = require('./input');
var _input2 = _interopRequireDefault(_input);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
console.log(_input2.default);
您可以看到每次访问 bar
被转换为访问 .default
。
You can see that every access to bar
is converted to access .default
.