欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

前端模块化 commonJs ES6 AMD CMD

程序员文章站 2022-06-13 22:02:11
...

前端模块化

学习网址
学习网址

模块化的开发方式可以提高代码复用率,方便进行代码的管理。通常一个文件就是一个模块,有自己的作用域,只向外暴露特定的变量和函数。目前流行的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

  1. CommonJs可以动态加载语句,代码发生在运行时
  2. CommonJs混合导出,还是一种语法,只不过不用声明前面对象而已,当我导出引用对象时之前的导出就被覆盖了
  3. CommonJs导出值是拷贝,可以修改导出的值,这在代码出错时,不好排查引起变量污染

Es Module

  1. Es Module是静态的,不可以动态加载语句,只能声明在该文件的最顶部,代码发生在编译时
  2. Es Module混合导出,单个导出,默认导出,完全互不影响
  3. Es Module导出是引用值之前都存在映射关系,并且值都是可读的,不能修改