Open fanxinjie opened 2 years ago
模块化是指把一个复杂的系统分解到多个模块以方便编码。
很久以前,开发网页要通过命名空间的方式来组织代码,例如 jQuery 库把它的API都放在了 window.$ 下,在加载完 jQuery 后其他模块再通过 window.$ 去使用 jQuery。 这样做有很多问题,其中包括:
window.$
jQuery
当项目变大时这种方式将变得难以维护,需要用模块化的思想来组织代码。
最初写代码的时候,没有学习模块管理,基本上都是暴力写,记得每次都会定义好多function,心想反正就几个方法,名称应该不会重复,随着手法的放飞自我还有代码的放飞自我,方法名甚至会出现asd1, asd2,放到现在怕是能被打死。
CommonJS 是一种使用广泛的 JavaScript 模块化规范,核心思想是通过 require 方法来同步地加载依赖的其他模块,通过 module.exports 导出需要暴露的接口。 CommonJS 规范的流行得益于 Node.js 采用了这种方式,后来这种方式被引入到了网页开发中。需要注意的是,CommonJS 规范的主要适用场景是服务器端编程,所以采用同步加载模块的策略。如果我们依赖3个模块,代码会一个一个依次加载它们。
采用 CommonJS 导入及导出时的代码如下:
// 导入 const moduleA = require('./moduleA'); // 导出 module.exports = moduleA.someFunc;
CommonJS 的优点在于:
CommonJS 的缺点
CommonJS 还可以细分为 CommonJS1 和 CommonJS2,区别在于 CommonJS1 只能通过 exports.XX = XX 的方式导出,CommonJS2 在 CommonJS1 的基础上加入了 module.exports = XX 的导出方式。 CommonJS 通常指 CommonJS2。
AMD 也是一种 JavaScript 模块化规范,与 CommonJS 最大的不同在于它采用异步的方式去加载依赖的模块。 AMD 规范主要是为了解决针对浏览器环境的模块化问题,最具代表性的实现是 require.js。
采用 AMD 导入及导出时的代码如下:
// 定义一个模块 define('module', ['dep'], function(dep) { return exports; }); // 导入和使用 require(['module'], function(module) { });
AMD 的优点在于:
AMD 的缺点在于JavaScript 运行环境没有原生支持 AMD,需要先导入实现了 AMD 的库后才能正常使用。
CMD是在AMD基础上改进的一种规范,和AMD不同在于对依赖模块的执行时机处理不同,CMD是就近依赖,而AMD是前置依赖。在CMD中,一个模块就是一个文件。最具代表性的实现是 sea.js。
// a.js define(function (require, exports, module){ exports.a = 'hello world'; }); // b.js define(function (require, exports, module){ var moduleA = require('./a.js'); console.log(moduleA.a); // 打印出:hello world });
ES6 模块化是欧洲计算机制造联合会 ECMA 提出的 JavaScript 模块化规范,它在语言的层面上实现了模块化。浏览器厂商和 Node.js 都宣布要原生支持该规范。它将逐渐取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
CommonJS
AMD
ES6的设计思想是尽量的静态化,使得编辑时就能确定模块的依赖关系,以及输出和出入的变量。CommonJS 和 AMD 都只能在运行时确定这些东西。
采用 ES6 模块化导入及导出时的代码如下:
// 导入 import { readFile } from 'fs'; import React from 'react'; // 导出 export function hello() {}; export default { // ... };
其中 import { readFile } from 'fs' 相当于
import { readFile } from 'fs'
let _fs = require('fs'); let readFile = _fs.readFile;
上述代码称为“运行时加载”,也就是完全加载整个模块,之后再读取对应的方法,只有运行时才会拿到这个对象,所以无法实现编译时静态化. 而 ES中的代码 import { readFile } from 'fs' 称为“静态加载”,即只加载 readFile 方法,相比之下静态加载效率更高。
ES6模块虽然是终极模块化方案,但它的缺点在于目前无法直接运行在大部分 JavaScript 运行环境下,必须通过工具转换成标准的 ES5 后才能正常运行。
着重说下第一个差异:
// export.js var counter = 3; function incCounter() { counter++; } module.exports = { counter: counter, get counter1() { return counter }, incCounter: incCounter, }; // import.js var mod = require('./export'); console.log(mod.counter); // 3 mod.incCounter(); console.log(mod.counter); // 3 console.log(mod.counter1); // 4 mod.incCounter(); console.log(mod.counter1); // 5
上面代码说明,lib.js 模块加载以后,它的内部变化就影响不到输出的 mod.counter 了。这是因为 mod.counter 是一个原始类型的值,会被缓存。除非写成一个函数,才能得到内部变动后的值。
lib.js
mod.counter
// export.js export let counter = 3; export function incCounter() { counter++; } // import.js import { counter, incCounter } from './export'; console.log(counter); // 3 incCounter(); console.log(counter); // 4
另一个例子验证 module 是动态加载的
// export.js export var a = 'asd'; setTimeout(() => a = 'asd111', 500); // import.js import {a} from './export.js'; console.log(a); setTimeout(() => console.log(a), 500); // 结果是 // asd, asd111
模块化
模块化是指把一个复杂的系统分解到多个模块以方便编码。
很久以前,开发网页要通过命名空间的方式来组织代码,例如 jQuery 库把它的API都放在了
window.$
下,在加载完jQuery
后其他模块再通过window.$
去使用jQuery
。 这样做有很多问题,其中包括:当项目变大时这种方式将变得难以维护,需要用模块化的思想来组织代码。
类模块化
Function
最初写代码的时候,没有学习模块管理,基本上都是暴力写,记得每次都会定义好多function,心想反正就几个方法,名称应该不会重复,随着手法的放飞自我还有代码的放飞自我,方法名甚至会出现asd1, asd2,放到现在怕是能被打死。
闭包
立即执行函数
CommonJS
CommonJS 是一种使用广泛的 JavaScript 模块化规范,核心思想是通过 require 方法来同步地加载依赖的其他模块,通过 module.exports 导出需要暴露的接口。 CommonJS 规范的流行得益于 Node.js 采用了这种方式,后来这种方式被引入到了网页开发中。需要注意的是,CommonJS 规范的主要适用场景是服务器端编程,所以采用同步加载模块的策略。如果我们依赖3个模块,代码会一个一个依次加载它们。
采用 CommonJS 导入及导出时的代码如下:
CommonJS 的优点在于:
CommonJS 的缺点
AMD
AMD 也是一种 JavaScript 模块化规范,与 CommonJS 最大的不同在于它采用异步的方式去加载依赖的模块。 AMD 规范主要是为了解决针对浏览器环境的模块化问题,最具代表性的实现是 require.js。
采用 AMD 导入及导出时的代码如下:
AMD 的优点在于:
AMD 的缺点在于JavaScript 运行环境没有原生支持 AMD,需要先导入实现了 AMD 的库后才能正常使用。
CMD
CMD是在AMD基础上改进的一种规范,和AMD不同在于对依赖模块的执行时机处理不同,CMD是就近依赖,而AMD是前置依赖。在CMD中,一个模块就是一个文件。最具代表性的实现是 sea.js。
ES6 模块化
ES6 模块化是欧洲计算机制造联合会 ECMA 提出的 JavaScript 模块化规范,它在语言的层面上实现了模块化。浏览器厂商和 Node.js 都宣布要原生支持该规范。它将逐渐取代
CommonJS
和AMD
规范,成为浏览器和服务器通用的模块解决方案。ES6的设计思想是尽量的静态化,使得编辑时就能确定模块的依赖关系,以及输出和出入的变量。
CommonJS
和AMD
都只能在运行时确定这些东西。采用 ES6 模块化导入及导出时的代码如下:
其中
import { readFile } from 'fs'
相当于上述代码称为“运行时加载”,也就是完全加载整个模块,之后再读取对应的方法,只有运行时才会拿到这个对象,所以无法实现编译时静态化. 而 ES中的代码
import { readFile } from 'fs'
称为“静态加载”,即只加载 readFile 方法,相比之下静态加载效率更高。ES6模块虽然是终极模块化方案,但它的缺点在于目前无法直接运行在大部分 JavaScript 运行环境下,必须通过工具转换成标准的 ES5 后才能正常运行。
ES6 与 CommonJS 差异
着重说下第一个差异:
上面代码说明,
lib.js
模块加载以后,它的内部变化就影响不到输出的mod.counter
了。这是因为mod.counter
是一个原始类型的值,会被缓存。除非写成一个函数,才能得到内部变动后的值。另一个例子验证 module 是动态加载的