Skip to content

模块化的规范

为了避免人为编排模块(依赖关系问题),逐步出现了一系列的工具库(模块化规范+模块化加载器)。不用再手动在HTML中引入代码模块。

CommonJs

CommonJs规范特点

  • CommonJS 主要运行于服务器端,该规范指出,一个单独的文件就是一个模块,其内部定义的变量是属于这个模块的,不会对外暴露,也就是说不会污染全局变量。 Node.js为主要实践者。

  • CommonJS 是同步加载模块的,模块加载的顺序,按照其在代码中出现的顺序。在服务器端,文件都是保存在硬盘上,所以同步加载没有问题,但是对于浏览器端,需要将文件从服务器端请求过来,那么同步加载就不适用了,所以,CommonJS是不适用于浏览器端的。
  • 模块可以多次加载,但只在首次加载时运行(单例模式),然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。(所以代码文件有改动的话,是需要重新启动程序的)

  • CommonJS输出是值的拷贝(require返回的值是被输出的值的拷贝,模块内部的变化也不会影响这个值)。

加载流程

  1. 检查 Module._cache,是否缓存之中有指定模块
  2. 如果缓存之中没有,就创建一个新的Module实例
  3. 将它保存到缓存
  4. 使用 module.load() 加载指定的模块文件,读取文件内容之后,使用 module.compile() 执行文件代码
  5. 如果加载/解析过程报错,就从缓存删除该模块
  6. 返回该模块的 module.exports

module、exports、require、global

CommonJS的核心思想就是通过 require 方法来同步加载所要依赖的其他模块,然后通过 exports 或者 module.exports 来导出需要暴露的接口。

js
const moduleA = require('module.a') //核心模块时,不需要带路径
module.exports = {}
const moduleA = require('module.a') //核心模块时,不需要带路径
module.exports = {}

AMD

AMD是Asynchronous Module Definition的缩写,意思就是"异步模块定义"。适用于浏览器

  • AMD 规范的实现主要是 RequireJS,它采用异步方式加载模块,模块的加载不影响它后面语句的运行,可以并行加载多个模块。

  • 必须提前加载所有的依赖,所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。(并且不能按需加载

  • require.config()指定引用路径等,用define()定义模块,用require()加载模块。

CMD

CMD(Common Module Definition),在JavaScript中,CMD 并不是一个常见的模块化规范。CMD规范是国内发展出来的(阿里SeaJS),SeaJS要解决的问题和requireJS一样,只不过在模块定义方式和模块加载时机上有所不同。

UMD

UMD(Universal Module Definition)= CommonJS + AMD + CMD 是一种通用的模块化规范,旨在兼容多种环境如:服务端、浏览器。

  • 它能够根据当前环境选择合适的模块加载方式,如 AMD、CommonJS 或全局变量。

  • UMD 提供了对多种模块加载规范的支持,使得模块可以在不同的环境中无缝运行。

  • UMD 不依赖于任何特定的模块加载器或库,可以独立使用。

ES Module

从 ES6 开始, JavaScript 才真正意义上有自己的模块化规范,ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。

ES Module规范特点

  • 静态化设计:ES Module 的设计思想是静态化,即编译时加载。在编译时就能确定模块的依赖关系、输入和输出的变量。这样的设计使得在运行时,引擎能够更快地处理模块加载,提高了执行效率。

  • 只读引用:相较于 CommonJS 的值拷贝,ES Module 采用的是值引用。当使用 import 命令引入模块时,得到的是一个只读引用,同时意味着模块内部的变化会反应在外部。

  • 严格模式:自动开启严格模式,提高了代码的安全性和可靠性 "use strict"。

  • 按需加载:当你使用 import 命令引入模块时,只有被引入的部分会被加载和执行,而不是整个模块。

  • 动态加载模块:使用 import() 函数可以在运行时动态加载模块,返回一个 Promise 对象。import() 类似于 Node.js 的 require() 方法,区别主要是前者是异步加载,后者是同步加载。

  • ES Module模块内的内容通过 cors 去请求外部js模块。

模块化对比

  1. AMD/CMD/CommonJs 是js模块化开发的规范,对应的实现是require.js/sea.js/Node.js。

  2. CommonJs 主要针对服务端,AMD/CMD/ES Module主要针对浏览器端(服务端一般采用同步加载的方式,浏览器端需要异步加载)。

  3. AMD/CMD区别:

都是异步加载js模块。

AMD 推崇依赖前置,CMD 推崇依赖就近。

AMD 是预加载,CMD是懒加载。

AMD无法满足按需加载,CMD支持按需加载。

  1. CommonJs和ES Module的区别:

CommonJS 模块输出的是一个值的拷贝,ES Module 模块输出的是值的引用。

CommonJS 模块是运行时加载,ES Module 模块是编译时输出接口。

CommonJS 模块的require()是同步加载模块,ES Module 模块的import命令是异步加载,有一个独立的模块依赖的解析阶段。

现阶段着重遵循CommonJS、ES Module

CommonJs语法

ES Module语法

export

export 命令能够对外输出的接口就是两类:

  1. 块级 { } :

    块级包裹的变量。(此处{ } 不是对象 ,是一个区块)

  2. var、let、const、function、class:

    带上关键字申明变量

js
let x = '1'
let y = '2'
let z = '3'
export { x,y,z }
export var a = 'a'
export let b = 'b'
export const c = 'c'
export function d() { }
export class E { }
let x = '1'
let y = '2'
let z = '3'
export { x,y,z }
export var a = 'a'
export let b = 'b'
export const c = 'c'
export function d() { }
export class E { }

export default

export default 相当于默认导出一个区块, 这个区块被命名为 default 的变量, 接收的时候时候可以自由命名

  1. { } :

此处{ }是对象行为

  1. 不能接 var、let、const

import

import 这里的 { } 并不是解构

js
import {a} from './xxx.js'
import {a} from './xxx.js'

Babel 转码器

Babel 是一个广泛使用的 ES6 转码器,可以将 ES6 代码转为 ES5 代码,从而在老版本的浏览器执行。这意味着,你可以用 ES6 的方式编写程序,又不用担心现有环境是否支持。

npm install --save-dev @babel/core
npm install --save-dev @babel/core