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