js 模块化总结
定义与场景
模块化简介
把一个复杂的项目, 划分为多个模块. 模块与模块之间通过 (AMD/CMD/ES6模块化/commonjs)等规范为纽带进行关联. 从而实现可维护可复用 的多个文件组成的项目.
模块化的特点: 可复用,可组合,独立性,中心化
模块化的作用:
- 解决了命名冲突 -- 隔离了模块内的变量作用域;
- 提高可维护性 -- 功能的拆分,使每个模块坚持单一职责原则,更方便维护
- 性能优化 -- 异步加载模块,减少浏览器的瞬间加载压力
模块化方案
常见的模块化方案有:
- CommonJs
- AMD
- CMD
- UMD
- ES6 模块化
CommonJs规范
内容参考 javascript.ruanyifeng.com/nodejs/modu...
来源: CommonJs 是以在浏览器之外的环境构建Javascript生态系统为目的而产生的项目,比如在服务器和桌面环境中。
这个项目最开始是 Mozilla 的工程师Kevin Dangoor 在2009年1月创建的,当时的名字是 ServerJS。Kevin Dangoor's What Server Side JavaScript needs 后来在2009年的8月更名为 CommonJs 。
CommonJs是一个规范,它的创建与核准是开放的。目前已经有了多种实现,通过依赖也支持构建在浏览器环境也可以使用的 CommonJs语法
使用场景
- 服务器环境 ---> node
- 浏览器环境 ---> Browserify
- 项目编译打包 ---> webpack
CommonJs特点
- 每个文件都是独立的,都有独立的 作用域。不会污染全局空间
- 文件可被重复引用加载。首次加载是会缓存, 之后加载就直接读取缓存
- 导入模块时 输出的模块是拷贝的。 一旦这个值被输出,模块内的变换不会影响已经输出的值
CommonJs 使用
CommonJs 每个模块(js文件)都默认存在 module.exports,
exports,
require
三个核心变量;
module.exports,
与 exports,
代码负责对模块的内容进行到处
require
函数用于对其他模块的内容进行导入
- module 记录当前模块信息。
- require 引入模块的方法。
- exports 当前模块导出的属性
导出 add.js
js
function isNumber (val) {
return typeOf (val) == "number"
}
function add (a, b) {
if (isNumber(a) && isNumber(b)) {
return a + b
} else {
throw new Errow('a and b must be a Number')
}
}
// module.exports 也可以写为 exports 建议只是用module.exports, 不要两个都用。
module.exports.add = add
导入 index.js
js
const { add } = require('./add.js')
console.log(add(1, 2))
commonJs是同步加载的 只有加载完成,才能执行后面的操作
require函数的加载过程: 先从缓存里找,有就加载 缓存没有就检查是不是全局模块,是就直接加载 不是就检查模块路径有没有该文件,有就解析路径并定位文件,然后执行加载 如果以上都不是,就沿当前路径向上层逐级递归查找,直到根目录 node_modules
AMD
内容参考 javascript.ruanyifeng.com/nodejs/modu...
来源: CommonJs 是以在浏览器之外的环境构建Javascript生态系统为目的而产生的项目,比如在服务器和桌面环境中。
这个项目最开始是 Mozilla 的工程师Kevin Dangoor 在2009年1月创建的,当时的名字是 ServerJS。Kevin Dangoor's What Server Side JavaScript needs 后来在2009年的8月更名为 CommonJs 。
CommonJs是一个规范,它的创建与核准是开放的。目前已经有了多种实现,通过依赖也支持构建在浏览器环境也可以使用的 CommonJs语法
使用场景
- 服务器环境 ---> node
- 浏览器环境 ---> Browserify
- 项目编译打包 ---> webpack
CommonJs特点
- 每个文件都是独立的,都有独立的 作用域。不会污染全局空间
- 文件可被重复引用加载。首次加载是会缓存, 之后加载就直接读取缓存
- 导入模块时 输出的模块是拷贝的。 一旦这个值被输出,模块内的变换不会影响已经输出的值
CommonJs 使用
CommonJs 每个模块(js文件)都默认存在 module.exports,
exports,
require
三个核心变量;
module.exports,
与 exports,
代码负责对模块的内容进行到处
require
函数用于对其他模块的内容进行导入
- module 记录当前模块信息。
- require 引入模块的方法。
- exports 当前模块导出的属性
导出 add.js
js
function isNumber (val) {
return typeOf (val) == "number"
}
function add (a, b) {
if (isNumber(a) && isNumber(b)) {
return a + b
} else {
throw new Errow('a and b must be a Number')
}
}
// module.exports 也可以写为 exports 建议只是用module.exports, 不要两个都用。
module.exports.add = add
导入 index.js
js
const { add } = require('./add.js')
console.log(add(1, 2))
commonJs是同步加载的 只有加载完成,才能执行后面的操作
require函数的加载过程: 先从缓存里找,有就加载 缓存没有就检查是不是全局模块,是就直接加载 不是就检查模块路径有没有该文件,有就解析路径并定位文件,然后执行加载 如果以上都不是,就沿当前路径向上层逐级递归查找,直到根目录 node_modules
commonJs最大的弊端就是同步加载。这在浏览器环境下是很可怕的。因为浏览器读取文件都是从服务器远程调用的 这无疑是对性能的极大消耗。但是不可否认commonjs 思想对与前端模块化开发 的影响与历史地位
Es6模块化
es6 模块化的优点 编译时加载
即 ES6 可以在编译时就完成模块加载,效率要比 CommonJS 模块的加载方式高
js
// es6 模块化
import {a, b, c} from './utils.js'
// 直接从utils加载 a, b, c 三个属性。 不会加载模块的其他属性 即 (编译时加载)
js
// common 模块化
const {a, b, c} = require('./utils.js')
// 加载模块的所有属性 生成一个对象 从对象中读取 a, b, c 三个属性
es6模块化 使用
导出 add.js
js
// 单独导出
export function isNumber (val) {
return typeOf (val) == "number"
}
export function add (a, b) {
if (isNumber(a) && isNumber(b)) {
return a + b
} else {
throw new Errow('a and b must be a Number')
}
}
// 导出多个
export default var a = { add }
导入 index.js
js
import { add } from './add.js'
console.log(add(1, 2))
异步导入
js
import('./add.js').then(({add}) => {
console.log(add(1, 2))
}).catch()
异步导入在webpack打包优化时的常见手段
ES6 Module 和 CommonJS 的区别:
-
ES6 Module 的 import 是静态引入,CommonJS的 require 是动态引入
-
Tree-Shaking 就是通过 ES6 Module 的 import 来进行静态分析,并且只支持 ES6 Module 模块的使用。 Tree-Shaking 就是移除掉 JS 上下文中没有引用的代码,比如 import 导入模块没有返回值的情况下,webpack 在打包编译时 Tree-Shaking 会默认忽略掉此文件 (webpack4 commonJs不可以; webpack5中已经对 commonJs提供支持)
-
ES6 Module 是对模块的引用,输出的是值的引用,改变原来模块中的值引用的值也会改变;CommonJS 是对模块的拷贝,修改原来模块的值不会影响引用的值
-
ES6 Module 里的 this 指向 undefined;CommonJS 里的 this 指向模块本身
-
ES6 Module 是在编译时确定依赖关系,生成接口并对外输出;CommonJS 是在运行时加载模块
-
ES6 Module 可以单独加载某个方法;CommonJS 是加载整个模块
-
ES6 Module 不能被重新赋值,会报错;CommonJS 可以重新赋值(改变 this 指向)