Node.js 和 ES6 中的 module.exports 与 export default

Posted

技术标签:

【中文标题】Node.js 和 ES6 中的 module.exports 与 export default【英文标题】:module.exports vs. export default in Node.js and ES6 【发布时间】:2017-03-10 17:50:45 【问题描述】:

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

什么不起作用

'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

【问题讨论】:

点赞,因为发现一个黑幕粉丝感觉真好 也为问题和马歇尔投了赞成票! 【参考方案1】:

Felix Kling 对这两者进行了很好的比较,任何想知道如何在 nodejs 中使用 module.exports 的命名导出旁边的导出默认

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

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

【讨论】:

假设initDAO需要对象DAO。我必须自己导入当前文件吗?或者我可以打电话给this.DAO()【参考方案2】:

你需要在你的项目中正确配置 babel 才能使用 export default 和 export const foo

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

然后在 .babelrc 中添加下面的配置

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

【讨论】:

我相信这个插件只是为了支持语法export someName from './someModules.js';【参考方案3】:

问题在于

如何在 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:我没有搜索 tbh(我感到羞耻 :( )。当然有关于同一个问题的问题,但以不同的方式提出。如果你找到合适的东西,请告诉我! 好的,花了一些时间才找到这些,但你现在可以使用你新获得的力量并选择How to correctly use ES6 “export default” with CommonJS “require”? 和Can't require() default export value in Babel 6.x 之一作为欺骗目标:-) 讽刺的是我现在能做到这一点:D @djKianoosh:See for yourself。赋值给module.exports 后,exportsmodule.exports 的值不同,所以赋值给exports.defaults 没有效果(因为导出的是module.exports)。换句话说,就好像你只做了module.exports = ... 一样。 我们如何导出默认值和命名值,以便这两者都可以在客户端代码端工作:ES6 -> import library, a, b, c from "library"; , commonJS -> const library = require("library"); const a, b, c = require("library")?就像React 一样,在使用 ES6 时我们可以做到 import React, useEffect, useState from "react";,而在使用 commonJS 时我们可以做到 const React = require("react"); const useEffect, useState = require("react");... 在编写自己的库时如何实现相同的目标?谢谢!

以上是关于Node.js 和 ES6 中的 module.exports 与 export default的主要内容,如果未能解决你的问题,请参考以下文章

Node.js 的 commonJS 规范 ES6 导入 js 文件

Node.js 的 commonJS 规范 ES6 导入 js 文件

markdown Node.js中的自定义ES6错误

es6和node.js模块的区别

如何欺骗 Node.js 将 .js 文件加载为 ES6 模块?

在 ES6 Node.js 中导入“.json”扩展会引发错误