Skip to main content

exports、export 和 export default

· 6 min read
Robbie Han

前言

exports 和 module.exports这篇博客中,我们详细解释了在 CommonJS 规范中exportsmodule.exports的区别。本篇博客将讨论 CommonJS 规范和 ES6 规范模块导出之间的关系。

export 和 export default

ES6 导出模块一般会使用exportexport default,使用两者的语法在 javaScript 文档中的ES6 Module已经做了详细的讲解,此处不再赘述。那么为什么已经有了export还要整个export default呢?exportexport default之间的关系是什么呢?下面的内容也将通过这两个问题进行展开。

为什么已经有了 export 还要整个 export default 呢?

在 ES6 模块中,如果模块导出中使用export var name = 'Robbie',那么在导入改模块的时候,导入的变量必须与之相对应,即import {name} form Info。而export default name在模块导入时的导入变量的命名可是任意的import myName form Info。对比两者来看使用export default可能具有更高的灵活性,也更便于不熟悉该库的开发者进行开发。

export 和 export default 之间的关系是什么呢?

我们知道浏览器是不支持 ES6 模块语法的,所以对于代码中的 ES6 模块一般是采用 Babel 转成 CommonJS 规范的代码。此时的代码虽然浏览器仍然不能执行,但是 Node 可以,因为 webpack 是基于 Node 构建的,所以我们可以通过 webpack 将代码打包成浏览器支持的 ES5 代码。

图:ES6模块转浏览器可执行代码示意图

为了探索 ES6 模块中exportexport default这两个之间的关系,我们可以看下面这个例子

export var info = {age: 22, name: 'han'};
var email = 'xiaoming@tmf-map.com';
export default email;

Babel 转义后:

'use strict';

Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.default = exports.info = void 0;
var info = {
age: 22,
name: 'han',
};
exports.info = info;
var email = 'SA17225105@gmail.com';
var _default = email;
exports.default = _default;

通过转义后的结果我们可以看出,模块导出会先定义一个exports对象,然后再将要导出的元素挂在这个对象上。

看到例子中的这个 exports 我们不仅会想到两个问题:

  1. ES6 在模块导入的时候会是个什么情况?
  2. 在项目中曾看到过exportexports混用的情况,它们两个一样吗?有什么联系?

ES6 在模块导入的时候会是个什么情况?

从 ES6 模块的导出结果可以看出,模块导出的时候是一个对象。对于export导出的变量,导入的时候通过需要用{}包裹,且导入和导出使用相同的变量名,这个很像 ES6 对象的解构,这个很好理解。而对于export default导出的变量的,导入的行为可能会令人费解,为什么可以不用{}包裹直接import,还可以任意的命名?

下面我想通过一个例子来探究一下对于export default导入的具体细节。

import email from 'myInfo';
console.log(email);

Babel 转义后:

'use strict';

var _myInfo = _interopRequireDefault(require('myInfo'));

function _interopRequireDefault(obj) {
return obj && obj.__esModule
? obj
: {
default: obj,
};
}

console.log(_myInfo.default);

从模块导出中可以看出__esModule的值为 true,所以模块导入的是一个“对象”。而从我们转义后的内容中也可以看出,转义后的内容和我们定义的email没有半毛钱关系,我们在使用email时,其实取到是_myInfo.default。这也解释了为什么我们导入的时候可以使用任何自定义的变量名。

在项目中曾看到过exportexports混用的情况,它们两个一样吗?有什么联系?

exportexports属于不同的规范,显然不是一回事。如果在项目中导出模块混用exportexports,模块在转义和打包的时候会将里面的代码统统打包成浏览器支持运行的 ES5 代码。

但是还是不建议混写两者,一方面容易使人懵逼,另一方面两个规范的输出规则是完全不一样的。

ES6 模块与 CommonJS 模块的差异

关于 ES6 模块与 CommonJS 模块的差异可以参考ES6 Module这一篇的文章。

如果对 ES6 模块和 CommonJS 模块打包后的内容感兴趣,可以结合下面这两个文件一起研究:

参考资料