Skip to content

第十三章 模块化

模块系统为了兼容性,大量运用ES5作用域语法,即IIFE

script标签的type=module时,是strict模式

模块标准的分类

  • 第三方标准(ES5)

    • CMD (Common Module Definition, 普通模块定义)

      对应CommonJS实现,对标服务器环境

    • AMD (Asynchronous Module Definition, 异步模块定义)

      对标受延迟限制的客户端环境

    • UMD(Universal Module Definition, 通用模块定义)

  • 原生标准(ES6+)

    • ESM(ECMAScript Module)

      浏览器环境

CMD模块

特点:

  • 服务器端环境

  • 同步加载

  • 支持动态依赖加载(类似python

  • 加载缓存(初次加载后生成缓存

  • 全局单例

  • 依赖全局对象require、export、module

  • 不可直接在浏览器中使用;如需在浏览器中使用,需要提前打包

AMD模块

特点

  • 受延迟限制的客户端环境(并不专门针对浏览器环境

  • 函数包装模块定义

  • 可以用字符串指定依赖

  • 支持require、exports对象

  • 支持动态依赖

UMD模块

目的:统一CJS和AMD系统,实现两个生态共存

流程:

  1. 启动时检测模块系统
  2. 对需要的模块系统进行配置
  3. 将逻辑封装在IIFE中

ESM模块系统

模块标签:

  • 给script添加type=module,浏览器将会把该脚本当为模块执行;

  • 执行顺序同defer相同——可以类比为宏任务,立即下载文件,文档解析完毕后执行;

    单设置defer的效果:原始script优先加载和执行->defer按顺序加载->等待文档解析完毕后执行

    单设置async的效果:原始script优先加载和执行->async无序加载->不等待文档解析,直接执行

  • 模块层面上,同步加载执行

  • 模块加载为单例——多次加载只视为一次

    *设置type为module后,import只能在外部的js文件中使用,不能在内联script中使用

    *在script上设置nomodule属性以解决浏览器兼容问题

模块加载

整个流程类似于AMD加载

  1. 浏览器异步加载整个依赖图
  2. 确定入口模块->确定依赖->请求资源
  3. 递归加载子依赖

特点:

  • 支持循环依赖(所有模块都支持) / 单例加载 / 子依赖 /
  • 默认为严格模式
  • 顶级this为undefined,var声明不会到window对象中
  • 异步加载 && 异步执行
  • 独立作用域

导入与导出

导出:默认导出 && 具名导出 && 别名导出 / 转移导出

导入: 默认导入 && 成员导入 && 别名导入 && 批量导入&&直接导入


将功能分割成不同独立的文件

划分独立作用域

历史演变

AMD require.js =>CMD sea.js=>COMMONJS =>NODE.JS=>UMD

模块练习

模块分导出部分和导入部分

js
向外部提供数据,称之为导出
moudle.define(a,b,function(){
    return {
        xxx
    }
})

写入新方法,成为导入。
moulde.define(c,d,function(){})
js
模块只有在初始化的时候才会执行
后续使用的时候是使用初始化之后的结果
初始化过程也是按顺序执行,如果拥有多个存在依赖的模块,那么会按照先后顺序共用一个模块。相当于传址共用一片内存地址。
js
		let demo = (function () {
        const mouduleList = {};
        function define(name, modules, action) {
            modules.map((m, i) => {
                modules[i] = mouduleList[m]
            })
            mouduleList[name] = action.apply(null, modules);
        }

        return { define };
    })()
    demo.define("yang", [], function () {
        return {
            first(arr) {
                return arr[0];
            },
            max(arr, key) {
                return arr.sort((a, b) => b[key] - a[key])[0];
            }
        }
    });
    demo.define("lesson", ["yang"], function (yang) {
        let data = [{ lesson: "english", price: 50 }, { lesson: "math", price: 250 }, { lesson: "arts", price: 75 }];;
        let res = yang.max(data, 'price');
        console.log(res);
    });

属性名,函数依赖,主体功能


模块使用

js
前提:script标签添加 module属性
<script></script type="module">
导入:
import{obj1} from '文件路径&文件名'
导出:
export{obj1,obj2,obj3...}

tips:导入中路径必须有./ ../等严格遵循规范

    import {demo} from "./jsPracticeCode.js"
    demo.show()
想要使用的前提是:1、scirpt拥有module标签 2、属性设置导出 3、属性导入

模块延迟解析与严格模式

js
模块延迟解析:
	放哪都行,后解析。
使用模块时,默认为严格模式

作用域

js
*模块具有其独立作用域

预解析

js
无论输出/调用多少次,只解析一次。
file1:
<script type="module">
    import { obj } from "./ts.js"
    console.log(obj.get());
</script>

file2:
class lesson {
    data = [];
    init() {
        this.data = [
            { name: "js" }, { name: "vue.js" }
        ]
    }
    get() {
        return this.data;
    }
}
let obj = new lesson();
obj.init();
export { obj };

导入与导出

js
具名导出:
func_file:
export let text = "text file";
export function get_a() {
    return "a";
}
export class Render {
    static render() {
        return "user render"
    }
}
main_file:
<script type="module">
    import { text,get_a,Render} from "./ts.js"
    console.log(get_a());
    console.log(text);
    console.log(Render.render())
<_/script>
js
批量导入
import * as obj from "address"
导出的是address文件所有导出的接口
js
别名使用
	导入别名:
	import {obj} as xxx from "";

	导出别名:
    export {obj} as xxx from ""
js
默认导出
	export default xxxxxx
	export {xxx as default } from ""
接收时可以随便使用变量来接收
	import whatever from ""
js
混合导出:
	具名与默认混合
import 默认,{具名} from "xxx"
不带花括号是默认导出,加上花括号为具名导出
	全部与默认混合:
	import * as api from "xxx"
	api.default()为调用默认
js
独立模块*n=>模块包=>导入模块包

批量导出:
tool_file
import * as a1 from "";
import * as a2 from "";

use_file
import * as api
api.a1.xxx
api.a2.xxx

规范

js
一般是文件名与模块相关联
公司有要求必须要根据公司的
一般为醒目易懂的英文名称

按需加载

js
按需加载是动态加载
import()函数可以按需加载(判断条件)

WebPack打包

js
将写好的es6+代码转换为兼容es5的代码。
需要下载node.js
记得先配置完再重启
js
webpack打包工具