CommonJS
Node 模块化遵循的是commonjs规范,CommonJs定义的模块分为: 模块标识(module)、模块导出(exports) 、模块引用(require)。
在node中,一个文件即一个模块,使用exports和require来进行处理。
导出形式有2种,module.exports 和 exports 导出:
// 第一种
module.exports = { // 需要导出的对象
....
}
// 第二种
exports.a = 'hello world';
// common.js文件里的this指向 module.exports
console.log(this === module.exports) // true
- 一个模块真正导出的是
module.exports
的值,exports
只是module.exports
的一个引用。通过exports.XXX
来修改module.exports.XXX
- 尽量使用只
module.exports
导入形式:
const index = require('./index');
require命令用于加载模块文件。require命令的基本功能是,读入并执行一个JavaScript文件,然后返回该模块的exports对象。如果没有发现指定模块,会报错。
module
module为该模块运行时生成的模块标识对象,标识该模块的一些信息。
module参数说明:
- id 为当前文件
- exports 为当前node文件模块儿导出的值
- parent 为父级调用的module对象,如果为null则该文件没有被调用
- filename 为当前文件名
- loaded 是否被加载
- children 引入模块数组,数组项格式同module
- paths 为node模块儿 node_modules 模块儿查找路径,一直查到根目录
最佳实践
- 导出对象时用module.exports
- 导出变量或方法时用exports
- exports与module.exports最好不要同时使用,exports不要重新赋值到新对象,否则引用无效。
ES6模块化
https://zh.javascript.info/import-export
常见的导出形式:
export default obj;
export const name = "hello world";
export { name1, name2, …, };
导入形式:
import obj, { name } from "./exp/exports";
export default
- 通过export方式导出,在导入时要加{ },export default则不需要
- export default表示一个模块默认的对外接口,一个模块只能有一个export default。
export default 和 export 导出的都是可以修改的。区别在于 export default 如果导出的是对象,则只能修改该对象下的属性,如果导出的是基本类型,则不能修改。export 不论导出的是对象还是基本类型,都是可以修改的。
as别名
在import和export中可以这样用:
export
export { name as hello };
import
import { hello as name } from './index';
最佳实践
1.当导出一个变量时,推荐使用export default。
2.当导出多个变量时,推荐使用export。
3.当需要导出多个变量且需要默认导出时,可以同时使用export和export default。
对比
- CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
- CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
- CommonJS 模块的require()是同步加载模块,ES6 模块的import命令是异步加载,有一个独立的模块依赖的解析阶段。
- ES6 模块之中,顶层的this指向undefined;CommonJS 模块的顶层this指向当前模块的输出
module.exports
,这是两者的一个重大差异。 - 循环加载:CommonJS 遇到循环依赖的时候,只会输出已经执行的部分,后续的输出或者变化,是不会影响已经输出的变量。而ES6模块相反,使用import加载一个变量,变量不会被缓存,真正取值的时候就能取到最终的值;
参考:
https://juejin.im/post/6844903945383444494 https://juejin.im/post/6844904067651600391 https://es6.ruanyifeng.com/#docs/module-loader
AMD
AMD是”Asynchronous Module Definition”的缩写,意思就是”异步模块定义”。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。其中 RequireJS 是最佳实践者。
使用define来定义模块,return来输出接口, require来加载模块
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {
exports.verb = function() {
return beta.verb();
//Or:
return require("beta").verb();
}
});
CMD
CMD(Common Module Definition - 通用模块定义)规范主要是Sea.js推广中形成的,一个文件就是一个模块,可以像Node.js一般书写模块代码。主要在浏览器中运行,当然也可以在Node.js中运行。
它与AMD很类似,不同点在于:AMD 推崇依赖前置、提前执行,CMD推崇依赖就近、延迟执行。
// a.js
define(function(require, exports, module) {
console.log('a.js执行');
})
// b.js
define(function(require, module, exports) {
console.log('b.js执行');
})
// index.js
define(function(require) {
var a = require('a');
var b = require('b');
console.log(a);
console.log(b);
})
UMD
UMD(Universal Module Definition - 通用模块定义)模式,该模式主要用来解决CommonJS模式和AMD模式代码不能通用的问题,并同时还支持老式的全局变量规范。
UMD 先判断是否支持 Node.js 的模块(exports)是否存在,存在则使用 Node.js 模块模式。再判断是否支持 AMD(define 是否存在),存在则使用 AMD 方式加载模块。
rollup的 umd 打包结果:
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Vue = factory());
})(this, (function () {
'use strict';
//...
}));