Node里面的模块系统遵循的是CommonJS规范。
CommonJS定义的模块分为:
1、模块标识(module)
2、模块定义(exports)
3、模块引用(require)
先解释 exports 和 module.exports
在一个node执行一个文件时,会给这个文件内生成一个 exports和module对象, 而module又有一个exports属性。他们之间的关系如下图,都指向一块{}内存区域。
exports = module.exports = {};
接下来上代码:
//utils.js let test = ‘today‘; console.log(module.exports); //能打印出结果为:{} console.log(exports); //能打印出结果为:{} exports.test = ‘tomorrow‘; //这里辛苦劳作帮 module.exports 的内容给改成 {test: ‘tomorrow‘} exports = ‘指向其他内存区‘; //然后在这里把exports的指向指到其他地方 //test.js let _test = require(‘/utils‘); console.log(_test) // 打印为 {test: ‘tomorrow‘}
1、由此可见,require导出的内容其实是module.exports的指向的内存块内容({test: ‘tomorrow‘}),并不是exports的内容(‘指向其他内存区‘)。
2、简而言之,区分他们之间的区别就是 exports 只是 module.exports的引用,exports是辅助module.exports操作内存中的数据用的,结果到最后真正被require出去的内容还是module.exports的。
为了避免糊涂,尽量都用 module.exports 导出,然后用require导入
先解释 export 和 export default
1、export与export default均可用于导出常量、函数、文件、模块等
2、在一个文件或模块中,export、import可以有多个,export default仅有一个
3、通过export方式导出,在导入时要加{ },export default则不需要
4、export能直接导出变量表达式,export default不行。
例如下面代码:
1、export (testExport.js)
‘use strict‘
//导出常量 export const a = ‘100‘; //导出函数方法 export const foo = function(){ console.log(‘This is a function foo‘); } //导出方法第二种 function bar(){ console.log(‘My name is bar‘); } export { bar }; // 相应的导入的方式为 import { foo, bar } from ‘./testExport‘; //导出了 export 方法 foo(); // 直接执行foo方法 bar(); // 直接执行bar方法
2、export default (testExportDefault.js)
‘use strict‘ //export default导出 const b = 100; export const foo = function(){ console.log(‘This is a function foo‘); } export default b // 也可以只导出一个对象 // export default {b, foo}; //export defult const b = 100;// 这里不能写这种格式,是错误的,可以导出一个对象, export default {b}。
综合应用:
//index.js
‘use strict‘ var express = require(‘express‘); var router = express.Router(); import { foo, too } from ‘./testExport‘; //导出了 export 方法 import b from ‘./testExportDefault‘; //导出了 export default import * as testExportModule from ‘./testExportDefault‘; //as 集合成对象导出 import * as testExportDefaultModule from ‘./testExportDefault‘; //as 集合成对象导出 foo(); bar(); testExportModule.foo(); console.log(b); console.log(testExportDefaultModule.b); // undefined , 因为 as 导出是 把 零散的 export 聚集在一起作为一个对象,而export default 是导出为 default属性。 console.log(testExportDefaultModule.default); // 100 or {b: 100, foo: function}
module.exports = router;
1、模块化的最佳实践
node.js 环境中,遵循 CommonJS 规范
浏览器环境中,遵循 ES Modules 规范
1.1、ES Modules 基本特性
自动采用严格模式,忽略 ‘use strict‘
每个 ESM 模块都是单的私有作用域
ESM 是通过 CORS 去请求外部 JS 模块的
ESM 的 script 标签会延迟执行脚本
ES Modules 注意事项
1.2、ES Modules 导出和导入
1.3、ES Modules in Node.js 支持情况:
面提到 ES6 模块和 CommonJS 模块有很大差异,不能直接混着写。这和开发中表现是不一样的,原因是开发中写的 ES6 模块最终都会被打包工具处理成 CommonJS 模块,以便兼容更多环境,同时也能和当前社区普通的 CommonJS 模块融合。
1、CommonJS的循环加载
想要搞清楚CommonJS的循环加载问题,首先我们要先大概了解下它的加载原理。CommonJS的一个模块,一般就是一个文件,使用reqiure第一次加载一个模块的时候,就会在内存中生成一个对象。
{
id: ‘...‘,
exports: { ... },
loaded: true,
...
}
CommonJS模块的特性就是加载时执行,当脚本被reqiure的时候,就会全部执行。一旦出现某个模块被"循环加载",就只输出已经执行的部分,还未执行的部分不会输出。
// a.js exports.done = false; // 首先输出一个done变量({done:false}),然后开始加载b.js,等待b.js执行完,才会继续执行后面的代码 var b = require(‘./b.js‘); console.log(‘在 a.js 之中,b.done = %j‘, b.done); exports.done = true; console.log(‘a.js 执行完毕‘); // b.js exports.done = false; var a = require(‘./a.js‘); //此时a里面只有 {done:false} console.log(‘在 b.js 之中,a.done = %j‘, a.done); exports.done = true; console.log(‘b.js 执行完毕‘); // main.js var a = require(‘./a.js‘); var b = require(‘./b.js‘); console.log(‘在 main.js 之中, a.done=%j, b.done=%j‘, a.done, b.done);
最后执行结果:
在 b.js 之中,a.done = false
b.js 执行完毕
在 a.js 之中,b.done = true
a.js 执行完毕
在 main.js 之中, a.done=true, b.done=true
2、ES6中的循环加载
ES6 模块是动态引用,如果使用import加载一个变量,变量不会被缓存,真正取值的时候就能取到最终的值
// even.js import { odd } from ‘./odd‘ export var counter = 0; export function even(n) { counter++; return n === 0 || odd(n - 1); } // even.js里面的函数even有一个参数n,只要不等于 0,就会减去 1,传入加载的odd()。odd.js也会做类似操作。 // odd.js import { even } from ‘./even‘; export function odd(n) { return n !== 0 && even(n - 1); } // 参数n从 10 变为 0 的过程中,even()一共会执行 6 次,所以变量counter等于 6 > import * as m from ‘./even.js‘; > m.even(10); true > m.counter 6
exports、module.exports和export、export default到底是咋回事,区别在哪里
原文:https://www.cnblogs.com/CandyDChen/p/14609313.html