type
status
date
slug
summary
tags
category
titleIcon
password
icon
calloutIcon
定义
模块化是一种代码组织方式,用于提高开发效率,降低维护成本。
模块化标准前的方式演进
基于文件划分的方式

html
javascript
javascript
javascript
- 一份文件就是一个模块,通过script标签引入使用
- 对其中变量的调用是对全局成员的调用
弊端
- 命名冲突
- 污染全局作用域
- 无法管理模块依赖关系
- 模块中所有成员都可以在外部访问修改
- 完全依靠约定的方式
命名空间方式
html
javascript
javascript
javascript
- 每个模块只暴露一个全局对象,所有模块成员挂载到全局对象下
- 相比于文件的方式将模块包裹在一个全局对象下实现,相当于添加了命名空间
弊端
命名冲突
污染全局作用域
- 无法管理模块依赖关系
- 仍没有私有空间,模块中所有成员都可以在外部访问修改
IIFE 立即执行函数方式
- 模块所有成员放在函数提供的私有作用域中
- 可以通过挂到全局对象的方式暴露成员
- 实现了私有成员(模块内部闭包访问) 外部无法直接使用
- 用IIFE参数作为依赖声明 使每个模块间依赖关系明显
html
javascript
javascript
javascript
总结
- 上述<基于文件,基于命名空间,IIFE>的方式均为早期没有工具与规范下的模块化落地实践
- 最后仍需要手动引入依赖,可能出现忘记引用或未删除不再引用的依赖
模块化标准
CommonJS
- 一个文件就是一个模块
- 每个模块具有单独作用域
- module.exports导出
- require导入
- 作为nodejs的默认模块标准,因为node在启动时加载模块,执行时不需要加载,所以是通过同步方式加载模块
但若在浏览器里使用会有大量同步请求
AMD规范 (Asynchronous Module Definition)
- 使用Require.js(https://requirejs.org/)作为模块加载器
- 通常用在浏览器中用于异步加载模块
NodeJS环境下示例
javascript
javascript
javascript
javascript
浏览器中异步原理:加载模块会创建script标签请求脚本执行模块代码
弊端
- 模块代码相对复杂
- JS文件请求次数多
CMD
- 通过sea.js作模块加载器
- 并不常见,模块处理参见:https://seajs.github.io/seajs/docs/#quick-start
ES Modules (ES6/2015后)
- 浏览器环境的默认,语言标准层面的模块化
- 通过script标签里type=”module”以ES Modules标准执行其中JS代码
- ES Modules自动采用严格模式,忽略”use strict”(非严格模式this打印全局对象,严格模式下为undefined)
- 每个ESM模块都是单独私有作用域
- 通过CORS请求获取外部JS资源(CORS不支持文件形式访问 需要http server方式)
- script标签延迟执行脚本,相当于defer效果(script默认立即执行,等待脚本加载完毕后继续渲染页面)
html
javascript



导入导出
- 一般导入导出
javascript
javascript
- 修饰成员声明导出与重命名
javascript
javascript
javascript
- 默认导出与引入
default关键字不能当变量使用
可以将某一变量当做默认导出
需要重命名default
导入时直接import变量名方式接收默认导出成员
typescript
javascript
并非导出对象(简写)与解构语法

export default接才是对象

验证


表达式错误

导出的是引用

javascript
commonjs后接导出对象,不是括号语法
javascript
require里接路径,不为名称
javascript
javascript
javascript
javascript
javascript
javascript
commonjs
CommonJS modules export values, while ES6 modules export immutable bindings.

import路径需要完整名称 commonjs可省
index.js不可省 commonjs可

文件路径名称使用打包工具打包模块时可省略扩展名 | index.js
如果省略/会认为是第三方模块 网页中引用可省 需要.开头 与commonjs一致

可绝对路径/开头 与 url引用

仅执行 不导入成员

提取全部成员 as放到一个对象中
每个成员都是对象一个属性

动态的路径 import 路径变量不可行

有时需要条件满足后再导入模块 也不能import
需要在最顶层 不能嵌套在其他作用域里

需要动态导入模块的机制
import函数
返回promise

同时导出模块默认成员与命名成员



直接导出导入成员
后续也就不再能使用这些成员


如果default导出需要index重命名,不然会作为index的default导出




es6 to es5 或 polyfill
使用unpkg获取js代码内容放入浏览器中使用

babel浏览器运行版本
es module loader 读出代码交给babel转换


支持esmodules的会执行两次
nomodule里只会在不支持es6 module的浏览器里工作


polyfill动态解析 效率差
应提前编译

原生使用esmodules


javascript
如果没有命名导出,可以先默认导出然后解构




原生不行



全局成员commonjs内置

esmodule里全都不能使用
都是commonjs在将模块包装成函数后通过参数提供进来的成员 esmodule中就没有这些提供了

替代方案
import export 对应前三
import.meta.url file协议的 文件url地址



包装成的函数的形参 伪全局对象
NodeJS中使用ES Modules
- 文件名命名为mjs
- 在package.json中设置”type”: “module”




preset-env包含所有新特性 插件集合

node_modules下.bin里有执行文件


preset一组插件

javascript
javascript
javascript
- 作者:CamelliaV
- 链接:https://camelliav.netlify.app/article/module
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。