直播课地址:
网上参考资料:[https://www.cnblogs.com/lvdabao/p/js-modules-develop.html]
早期无模块化的js项目
js的作用域很模糊,只有函数作用域,没有花括号块级作用域,可能导致多人协同开发时,如果重复命名,会用变量污染
1全局变量的污染
2,函数名称的污染
3,文件的依赖关系只能通过script标签层级引用
最早的模块化
(使用立即执行函数封装)
const lifeModule = (() => {
let count = 0;
return {
add: () => {
count++
},
reset: () => {
count = 0
}
}
})()
jQuery风格的匿名自执行函数
(function(window){ //代码 window.jQuery = window.$ = jQuery;//通过给window添加属性而暴漏到全局 })(window);
通过window挂载变量或者暴露接口到全局,如果有插件,则挂到名称空间JQuery上。
更加优雅,但是没有根本解决模块化问题。
模块依赖通过传参的方式
((dependency1,dependency2,...)=>{
.......
})(dependency1,dependency2,...)
缺点:模块的命名在全局暴露,依然会有污染风险
node孵化的时候,因为是服务器语言,需要模块化规范,于是发明了commonJs
规范特征:
通过exports方法对外暴露接口
通过require方法调用依赖模块
commonJS
优点:服务端解决了模块依赖,模块思想,全局污染的规范问题
缺电:因为是在服务端实现的规范,服务端1是同步加载模块文件的,不存在异步加载的先后问题,2是服务端代码是先编译后执行的,在离线编译的时候,模块之间的依赖关系都确认了。浏览器端的代码执行环境和服务端不一样。
AMD方式:AMD(Asynchronous Module Definition)
通过异步加载+允许定制回调函数
经典:require.js
requirejs中有专门define方法来定义模块,以解决模块异步加载问题
requirejs会等待所有模块依赖加载完毕,然后再执行模块
define(‘mymodule’,[dependency1,dependency2],(dependency1,dependency2)=>{
.......
})
AMD中使用revealing
define(id,[],(requie,export,module)=>{
const depen1=require('./otherModule')
export.func=()=>{
.......
}
})
优点:适合在浏览器端异步加载模块,可是并行加载多个模块
缺点:不能按需加载,会等待加载完引入的全部模块
CMD方式:
解决AMD不能按需加载的痛点
经典:sea.js
实现:CMD实现按需加载需要依赖打包工具,在打包编译阶段就按需加载对应模块内容
ES6,模块化
通过export关键字导出模块功能(暴露api)
通过import关键字导入模块(或者部分功能)
---otherModule.js
export.func1=()=>{...}
export.func2=()=>{...}
import{func1,func2} from './otherModule.js'
优点:官方统一了模块化规范和语法
缺点:还是没有从本质上解决例如异步,按需加载等需求
ES11
解决模块动态(异步)加载
类似promise语法。统一一个then方法,加载成功后调用then方法
由于以上模块化几乎全部在运行时进行,具有局限性
解决模块化新思路:前端工程化
离线打包(编译)
1,解析原始依赖,形成依赖树配置
2,运行时,这个依赖会发送到浏览器端
3,运行时根据依赖树加载依赖(如AMD方式)