CommonJs、AMD、CMD、ES6模块
模块化简介
模块化就是把系统分离成独立功能的方法,这样我们需要什么功能,就加载什么功能
- 每个模块都是独立的,良好设计的模块会尽量与外部的代码撇清关系,以便于独立对其进行改进和维护
- 可以重复利用,而不用经常复制自己之前写过的代码
模块化主要解决两个问题,“命名冲突”、“文件依赖”
命名冲突
// a.js
var a = 1;
// b.js
var a = 2;
文件依赖
// b.js依赖a.js,标签的书写顺序必须是:
<script src='a.js' type='text/javascript'></script>
<script src='b.js' type='text/javascript'></script>
解决冲突、依赖(按需加载)
使用命名空间
这样的写法会暴露所有模块内的成员,内部状态可以被外部改写
let module = {
name: 'likang xie',
sayName() {
console.log(this.name);
}
}
// 可以直接在外面修改这个对象的内容,安全性不好
立即执行函数+闭包
函数内部有自己独立的作用域,外部只能访问自己暴露的成员而不能读取内部的私有成员
let module = (function () {
let privateName = 'private'; // 私有变量
let privateFn = function () {}; // 私有函数
// 对外暴露的成员
return {
name: 'likang xie', // 公有属性
sayName() { // 公有方法
console.log(this.name);
}
}
})();
// 外部调用
module.sayName(); // likang xie
使用立即执行函数+类
const People = (function () {
let privateName = 'private'; // 私有变量
let fn = function () {}; // 私有方法
return class People {
constructor () {
this.name = 'likang xie'; // 公有变量
}
// 公有方法
sayName() {
console.log(this.name);
}
}
})()
CommonJs(用于Node环境,在服务器端使用)
根据CommonJs规范,每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见,CommonJS规范加载模块是同步的,也就是说,加载完成才可以执行后面的操作,Node.js主要用于服务器编程,模块一般都是存在本地硬盘中,加载比较快,所以Node.js采用CommonJS规范
定义模块
// module.js
let name = 'liakng xie';
let sayName = function () {
console.log(name);
};
module.exports = { name, sayName }
// 或者
exports.sayName = sayName;
加载模块
// 通过 require 引入依赖
let module = require('./module.js');
module.sayName(); // likang xie
注: const exports= module.exports;
exports只是module.exports的快捷方式。所有的exports收集到的属性和方法,都赋值给了Module.exports。当然,这有个前提,就是Module.exports本身不具备任何属性和方法。如果,Module.exports已经具备一些属性和方法,那么exports收集来的信息将被忽略。
总结:
- module.exports 初始值为一个空对象 {}
- exports 是指向的 module.exports 的引用
- require() 返回的是 module.exports 而不是 exports
AMD(用于浏览器环境)
AMD是"Asynchronous Module Definition"的简写,也就是异步模块定义。它采用异步方式加载模块。通过define方法去定义模块,require方法去加载模块。
定义模块
define(['module'], function() {
let name = 'likang xie';
function sayName() {
console.log(name);
}
return { sayName }
})
使用模块
// 通过 require 引入依赖
require(['module'], function(mod) {
mod.sayName(); // likang xie
})
ES6模块(用于浏览器环境)
定义模块
// a.js,输出一个变量
export default { name: 'likang xie' }
// b.js 输出多个变量
export let name = 'likang xie';
export let sayName = () => console.log(name);
// export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。
export var foo = 'bar';
setTimeout(() => foo = 'baz', 500);\
// 上面代码输出变量foo,值为bar,500 毫秒之后变成baz。
// CommonJS 规范完全不同。CommonJS 模块输出的是值的缓存,不存在动态更新
使用模块
import people from 'a.js';
console.log(people); // { name: 'likang xie' }
// 将所有获取到的变量存到people里
import * as people from 'b.js';
console.log(people); // 一个module对象 { name: 'likang xie', sayName: .... }
// 或者
import { name, sayName } from 'b.js';
由于import是静态执行,所以不能使用表达式和变量,这些只有在运行时才能得到结果的语法结构。
// 报错
import { 'f' + 'oo' } from 'my_module';
// 报错
let module = 'my_module';
import { foo } from module;
// 报错
if (x === 1) {
import { foo } from 'module1';
} else {
import { foo } from 'module2';
}
下面比较一下默认输出和正常输出。(即export default和export)
// 第一组
export default function crc32() { // 输出
// ...
}
import crc32 from 'crc32'; // 输入
// 第二组
export function crc32() { // 输出
// ...
};
import {crc32} from 'crc32'; // 输入
ES6 模块与 CommonJS 模块完全不同。
它们有两个重大差异。
- CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
- CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
第二个差异是因为 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
上一篇: Commonjs和Es6的导入导出
下一篇: 归并排序
推荐阅读
-
前端笔记之ES678&Webpack&Babel(下)AMD|CMD规范&模块&webpack&Promise对象&Generator函数
-
ES6与CommonJS中的模块处理的区别
-
再次梳理AMD、CMD、CommonJS、ES6 Module的区别
-
CommonJS、AMD、UMD、CMD使用介绍
-
详解CommonJS和ES6模块循环加载处理的区别
-
JavaScript模块化-CommonJS、AMD、CMD、UMD、ES6
-
前端模块化:CommonJS,CMD,AMD,ES6
-
一览js模块化:从CommonJS到ES6
-
详谈commonjs模块与es6模块的区别
-
详解搞清CommonJS、AMD、CMD、ES6的联系与区别