Node.js和ES6中的module.exports与export默认


317

Node module.exports和ES6 之间有什么区别export default?我试图弄清楚为什么export default在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

什么工作

'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

Answers:


401

问题是

  • 如何在CommonJS中模拟ES6模块
  • 您如何导入模块

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


我们没有这个的副本吗?
Bergi

3
@Bergi:我没有搜寻tbh(对我很可耻:()。对于相同的问题肯定有疑问,但是以不同的方式询问。让我知道你是否找到合适的东西!
Felix Kling

1
好的,花了一些时间找到了这些,但是现在您可以使用新获得的功能,并选择如何正确地将ES6“导出默认值”与CommonJS“要求”一起使用?并且不能要求Babel 6.x中的默认导出值作为重复目标:-)
Bergi,2016年

1
我现在能做到这一点真是讽刺:D
费利克斯·克林

1
@djKianoosh:自己看看。在分配给和之后module.exportsexportsmodule.exports具有不同的值,因此分配给exports.defaults无效(因为module.exports是导出的内容)。换句话说,它与您只做过的完全相同module.exports = { ... }
Felix Kling

1

您需要在项目中正确配置babel以使用export default和export const foo

npm install --save-dev @babel/plugin-proposal-export-default-from

然后在.babelrc中添加以下配置

"plugins": [ 
       "@babel/plugin-proposal-export-default-from"
      ]

1

Felix Kling在这两者之间进行了很好的比较,因为任何人都想知道如何在nodejs中如何将导出默认值与带有module.exports的命名导出一起使用

module.exports = new DAO()
module.exports.initDAO = initDAO // append other functions a named export

// now you have
let DAO = require('_/helpers/DAO');
// DAO by default is exported class or function
DAO.initDAO()

-61

tl; dr现在可以正常使用,SlimShady必须使用Babel使用编译需要或导入的文件'use strict'

我在babel-cli最初遇到此错误的项目中使用6.18.0。

没有'use strict'是坏消息熊

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

请“严格使用”

'use strict'
import SlimShady from './slim-shady'
var marshall = new SlimShady()  // all good in the hood

13
这是没有道理的。每个使用import声明的源都是一个模块,而那些已经是严格的。实际的区别在于要求与导入。
Bergi

1
有意义的是使用import代替requireexport default代替exports.default
Corey Alix


104
这必须是我在stackoverflow上见过的最不满意的答案
Jimi

4
@Jimi那是因为它是整个网站上投票率第四低的答案。
pppery
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.