-
module.exports、exports是commonjs的规范。
-
export、export default是es6规范。
-
require是AMD规范引入方式。
-
import是es6的一个语法标准。
module.exports和exports
module.exports和exports:
针对基础数据类型是值的拷贝,导出复杂数据类型时浅拷贝该对象。
理解概念:
-
module.exports:在module对象中,包含exports属性,而我们就是通过module.exports向外暴露共享成员的。
-
exports:nodejs为了简化向外共享成员的代码,提供的一个新方式,
在默认情况下,exports和module.exports指向的是同一个对象。一般通过exports.xxx向外暴露成员,而直接给exports赋值毫无意义(不导出只在模块内生效)。console.log(module.exports);// {} console.log(exports);// {} console.log(module.exports === exports)// true
理解本质:
-
module.exports:向外暴露始终是module.exports对象属性值,不管暴露的是基础类型还是引用类型。
为什么module.exports导出的是一个值?
因为module.exports默认情况下指向的是一个Object对象,而现在直接赋值给module.exports一个新的数据类型,比如下面例子中导出一个基础类型a,不管是引用类型还是基础类型,导出是什么就是什么。
// test1.js const a = 1; module.exports = a; console.log(exports);// {} // test2.js const a = require('./test1'); console.log(a);// 1 -
exports:exports直接赋值向外暴露成员是毫无意义的,因为
不管是exports还是module.exports向外暴露成员最终都是以module.exports为准。// test1.js exports = 1; console.log(module.exports);// {} // test1.js const a = require('./test1'); console.log(a);// {}为什么exports导出的是一个对象?
因为module.exports与exports指向的都是同一个对象,exports.xxx的意义就是给对象module.exports内的属性xxx赋值,也就是说
exports.xxx等同于module.exports.xxx,而下面的例子就可以解析得清楚了。// test1.js exports.a = 1; console.log(module.exports);// {a:1} // test2.js const a = require('./test1'); console.log(a);// {a:1}
export和export default
export和export default:
模块输出的是值的引用。
// export 和 export default用法
export default fs
export const fs
export function readFile
export {readFile, read}
export * from 'fs'
-
export:一个模块就是一个独立的文件。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。也就是说
可以导出多个属性。// test1.js export const a = 1; export const arr = [1, 2, 3]; export const fun = () => { console.log("fun method!"); } // test2.js import { a, arr, fun } from "./test1" console.log(a);// 1 console.log(arr);// [1,2,3] fun();// fun method! -
export default:为模块指定默认输出,有且仅有一个属性导出。注意地,
如果export与export default同时存在时,主要看import导入方式:import xxx from ""就导入export default;import {xxx} from ""就导入多个export导出属性。一般来说,尽量不要混在一起用,以防搞混。// test1.js export const a = 1; const b = 2; export default b; // test2.js import a from "./test1" console.log(a);// 2 // import { a } from "./test1" // console.log(a); 1
require和import
-
require:
运行时加载,导入的是exports(exports|module.exports)导出的内容。// test1.js let a = 2; module.exports = a; // test2.js const a = require('./test1'); console.log(a);// 2 -
import:
编译时加载,由于是编译时加载,所以import命令会提升到整个模块的头部。导入的是export(export|export default)导出的内容。// import 导入的用法 import fs from 'fs' import {readFile} from 'fs' //从 fs 导入 readFile 模块 import {default as fs} from 'fs' //从 fs 中导入使用 export default 导出的模块 import * as fileSystem from 'fs' //从 fs 导入所有模块,引用对象名为 fileSystem import {readFile as read} from 'fs' //从 fs 导入 readFile 模块,引用对象名为 read // import(modulePath) import('').then()//动态导入模块 // 表达式加载模块并返回一个 promise,该 promise resolve 为一个包含其所有导出的模块对象。
require/exports和import/export区别?
-
出处不同:
类型 年份 出处 require/exports 2009 CommonJS import/export 2015 ECMAScript2015(ES6) -
兼容性不同:
环境 require/exports import/export Node.js 所有版本 Node 9.0+ Chrome 不支持 61+ Firefox 不支持 60+ Safari 不支持 10.1+ Edge 不支持 16+
注意地,import/export在nodejs中使用时,Node 9.0+启动需加上 flag --experimental-modules) Node 13.2+(直接启动)
- 原生浏览器不支持 require/exports,可使用支持 CommonJS 模块规范的 Browsersify、webpack 等打包工具,它们会将 require/exports 转换成能在浏览器使用的代码。
- import/export 在浏览器中无法直接使用,我们需要在引入模块的script元素上添加type="module" 属性。
- 即使 Node.js 13.2+ 可以通过修改文件后缀为 .mjs 来支持 ES6 模块 import/export,但是Node.js 官方不建议在正式环境使用。目前可以使用 babel 将 ES6 的模块系统编译成 CommonJS 规范(注意:语法一样,但具体实现还是 require/exports)
-
require/exports 是运行时动态加载,import/export 是静态编译。
CommonJS 加载的是一个对象(即 module.exports 属性),该对象只有在脚本运行完才会生成。而ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。- 阮一峰 -
导入导出用法不同。
-
是否采用严格模式。import/export 导出的模块默认调用严格模式,require/exports 默认不使用严格模式,可以自定义是否使用严格模式。
-
引用位置限制。ES6 模块可以在 import 引用语句前使用模块,CommonJS 则需要先引用后使用
-
使用位置限制。import/export 只能在模块顶层使用,不能在函数、判断语句等代码块之中引用;require/exports 可以。