模块化之前的痛点
- 命名空间冲突
- 无法合理的管理项目的依赖和版本
- 无法方便的控制依赖的加载顺序
- **
Javascript包管理规范
CommonJS
通过 require 来引入模块,通过 module.exports 定义模块的输出接口
module.exports = … 只能输出一个,且后面的会覆盖上面的
exports. … 可以输出多个
运行阶段确定接口,运行时才会加载模块
模块是对象,加载的是该对象
加载的是整个模块,即将所有的接口全部加载进来
输出是值的拷贝,即原来模块中的值改变不会影响已经加载的值
ES6
使用 import 和 export 的形式来导入导出模块
export 可以输出多个,输出方式为 {}
export default 只能输出一个,可以与export 同时输出
解析阶段确定对外输出的接口,解析阶段生成接口
模块不是对象,加载的不是对象,是一个只读引用
等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值
可以单独加载其中的某个接口(方法)
静态分析,动态引用,输出的是值的引用,值改变,引用也改变
this 指向undefined
AMD
用define()函数定义模块
异步加载的方式来加载模块
可并行加载多个依赖
缺点是浏览器没有原生支持AMD规范,需要先导入实现AMD规范的库才能使用
模块语句定义在回调函数里,等到加载完成后再执行回调函数
AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块
AMD 在依赖模块加载完成后就直接执行依赖模
require.js 实现了 AMD 规范
define(["./a", "./b"], function(a, b) {// 依赖必须一开始就写好a.doSomething();b.doSomething();});
AMD规范允许输出的模块兼容CommonJS规范
define(function (require, exports, module){var someModule = require("someModule");var anotherModule = require("anotherModule");someModule.doTehAwesome();anotherModule.doMoarAwesome();exports.asplode = function (){someModule.doTehAwesome();anotherModule.doMoarAwesome();};});
CMD
对依赖的处理不同
对依赖模块的执行时机不同
在依赖模块加载完成后并不执行,只是下载而已,等到所有的依赖模块都加载好后,进入回调函数逻辑
遇到 require 语句 的时候才执行对应的模块
模块的执行顺序和书写顺序保持一致
sea.js 实现了 CMD 规范
define(function(require, exports, module) {// 依赖可以就近书写,控制模块的执行顺序var a = require("./a");a.doSomething();var b = require("./b");b.doSomething();// ...});
RequireJS
实现js文件的异步加载,避免网页失去响应
管理模块之间的依赖性,便于代码的编写和维护
动态创建 script 脚本来异步引入模块,然后对每个脚本的 load 事件进行监听,如果每个脚本都加载完成了,再调用回调函数
node = document.createElement("script");node.id = modName;node.type = "text/javascript";node.charset = "utf-8";node.async = true;node.src = url;fs = document.getElementsByTagName("script")[0];fs.parentNode.insertBefore(node, fs);node.onload=function(){const moduleName=node.getAttribute('data-requiremodule')catch[moduleName]=getscriptData(moduleName)}
Webpack模块化机制
兼容所有模块化方案
静态解析,按需打包,动态加载
