模块.exports与Node.js和ES6中的export default的关系

Node的module.exports和ES6的export default之间有什么区别?我想弄清楚为什么我在Node.js 6.2.2中尝试 "export default "时,会出现"__不是构造函数"的错误。

什么工作

'use strict'
class SlimShady {
  constructor(options) {
    this._options = options
  }

  sayName() {
    return 'My name is Slim Shady.'
  }
}

// This works
module.exports = SlimShady

什么是_doesn't_工作

解决办法

问题是与

  • ES6模块在CommonJS中是如何被模拟的
  • 你是如何导入模块的

ES6到CommonJS

在写这篇文章的时候,没有任何环境原生支持ES6模块。当在Node.js中使用它们时,你需要使用像Babel这样的东西来将模块转换为CommonJS。但这究竟是如何实现的呢?

许多人认为module.exports = ...等同于export default ...exports.foo ...等同于export const foo = ...。但这并不完全正确,至少Babel不是这样做的。

ES6的default出口实际上也是命名的出口,只不过default是一个"保留"的名字,并且有特殊的语法支持。让我们来看看Babel是如何编译命名和默认导出的。

// 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; 

这里我们可以看到,默认出口成为exports对象的一个属性,就像foo

导入模块

我们可以通过两种方式导入模块。要么使用CommonJS,要么使用ES6的import语法。

你的问题:我相信你正在做类似的事情。

var bar = require('./input');
new bar();

期待bar被分配到默认导出的值。但正如我们在上面的例子中所看到的,默认的出口被分配给了default属性!

所以为了访问默认导出,我们实际上要做的是

var bar = require('./input').default;

如果我们使用ES6模块语法,即

import bar from './input';
console.log(bar);

Babel会将其转化为

'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

评论(9)

tl;dr 现在,要想让它工作,需要或导入 "SlimShady "的文件必须使用Babel的"'use strict' "进行编译。

我在最初遇到这个错误的项目中使用babel-cli6.18.0。

没有'use strict'是坏消息熊。

var SlimShady = require('./slim-shady');
var marshall = new SlimShady();  // uh, oh...

'use strict', please

评论(6)