前端模块化 commonJs ES6 AMD CMD
前端模块化
模块化的开发方式可以提高代码复用率,方便进行代码的管理。通常一个文件就是一个模块,有自己的作用域,只向外暴露特定的变量和函数。目前流行的js模块化规范有CommonJS、AMD、CMD以及ES6的模块系统
commonJS
我们都知道在早期JavaScript模块这一概念,都是通过script标签引入js文件代码。当然这写基本简单需求没有什么问题,但当我们的项目越来越庞大时,我们引入的js文件就会越多,这时就会出现以下问题:
js文件作用域都是顶层,这会造成变量污染
js文件多,变得不好维护
js文件依赖问题,稍微不注意顺序引入错,代码全报错
JavaScript社区出现了CommonJs,CommonJs是一种模块化的规范,包括现在的NodeJs里面也采用了部分CommonJs语法在里面。那么在后来Es6版本正式加入了Es Module模块,这两种都是解决上面问题,那么都是解决什么问题呢。
解决变量污染问题,每个文件都是独立的作用域,所以不存在变量污染
解决代码维护问题,一个文件里代码非常清晰
解决文件依赖问题,一个文件里可以清楚的看到依赖了那些其它文件
并且导入的num的值我们也可以进行修改
动态导入(代码发生在运行时),不可以重复导入。
如果使用exports导出单个值之后,就不能在导出一个对象值,这只会修改exports的对象改变,然而修改无效,最终导出还是name,和sex,因为最终的导出是由module.exports决定的。
// 导出一个对象
module.exports = {
name: "蛙人",
age: 24,
sex: "male"
}
// 导出任意值
module.exports.name = "蛙人"
module.exports.sex = null
module.exports.age = undefined
//直接导出
exports.name = "蛙人"
exports.sex = "male"
导入
// index.js
module.exports.name = "蛙人"
module.exports.age = 24
let data = require("./index.js")
console.log(data) // { name: "蛙人", age: 24 }
动态导入
let lists = ["./index.js", "./config.js"]
lists.forEach((url) => require(url)) // 动态导入
if (lists.length) {
require(lists[0]) // 动态导入
}
Node.js是commonJS规范的主要实践者,它有四个重要的环境变量为模块化的实现提供支持:module、exports、require、global。实际使用时,用module.exports定义当前模块对外输出的接口(不推荐直接用exports),用require加载模块
// 定义模块math.js
var basicNum = 0;
function add(a, b) {
return a + b;
}
module.exports = { //在这里写上需要向外暴露的函数、变量
add: add,
basicNum: basicNum
}
// 引用自定义的模块时,参数包含路径,可省略.js
var math = require('./math');
math.add(2, 5);
// 引用核心模块时,不需要带路径
var http = require('http');
http.createService(...).listen(3000);
commonJS用同步的方式加载模块。在服务端,模块文件都存在本地磁盘,读取非常快,所以这样做不会有问题。但是在浏览器端,限于网络原因,更合理的方案是使用异步加载。
AMD
CMD
Es Module
在Es Module中导出分为两种,单个导出(export)、默认导出(export default),单个导出在导入时不像CommonJs一样直接把值全部导入进来了,Es Module中可以导入我想要的值。那么默认导出就是全部直接导入进来,当然Es Module中也可以导出任意类型的值。
而且导入的值,不能进行修改也就是只读状态
就是Es Module语句``import只能声明在该文件的最顶部,不能动态加载语句,Es Module`语句运行在代码编译时。
// 导出变量
export const name = "蛙人"
export const age = 24
// 导出函数也可以
export function fn() {}
export const test = () => {}
// 如果有多个的话
const name = "蛙人"
const sex = "male"
export { name, sex }
//混合导出
export const name = "蛙人"
export const age = 24
export default {
fn() {},
msg: "hello 蛙人"
}
导出
// index,js
export const name = "蛙人"
export const age = 24
import { name, age } from './index.js'
console.log(name, age) // "蛙人" 24
// 如果里面全是单个导出,我们就想全部直接导入则可以这样写
import * as all from './index.js'
console.log(all) // {name: "蛙人", age: 24}
//混合导入
//混合导入,则该文件内用到混合导入,import语句必须先是默认导出,后面再是单个导出,顺序一定要正确否则报错。
// index,js
export const name = "蛙人"
export const age = 24
export default {
msg: "蛙人"
}
import msg, { name, age } from './index.js'
console.log(msg) // { msg: "蛙人" }
//上面example中,如果导入的名称不想跟原本地名称一样,则可以起别名。
import { default as all, name, age } from './index.js'
console.log(all) // { msg: "蛙人" }
CommonJs和Es Module的区别
CommonJs
- CommonJs可以动态加载语句,代码发生在运行时
- CommonJs混合导出,还是一种语法,只不过不用声明前面对象而已,当我导出引用对象时之前的导出就被覆盖了
- CommonJs导出值是拷贝,可以修改导出的值,这在代码出错时,不好排查引起变量污染
Es Module
- Es Module是静态的,不可以动态加载语句,只能声明在该文件的最顶部,代码发生在编译时
- Es Module混合导出,单个导出,默认导出,完全互不影响
- Es Module导出是引用值之前都存在映射关系,并且值都是可读的,不能修改
上一篇: 开国皇帝刘秀功勋卓著,为什么知名度不高?
推荐阅读
-
前端笔记之ES678&Webpack&Babel(下)AMD|CMD规范&模块&webpack&Promise对象&Generator函数
-
再次梳理AMD、CMD、CommonJS、ES6 Module的区别
-
CommonJS、AMD、UMD、CMD使用介绍
-
JavaScript模块化-CommonJS、AMD、CMD、UMD、ES6
-
前端模块化:CommonJS,CMD,AMD,ES6
-
一览js模块化:从CommonJS到ES6
-
详解搞清CommonJS、AMD、CMD、ES6的联系与区别
-
前端模块化小总结—commonJs,AMD,CMD, ES6 的Module
-
Vue.js——前端模块化雏形和CommonJS——2020.12.9
-
前端模块化(CommenJS规范、ES6规范)