模块化

js 模块化历史

  • 早期的 Javascript 是没有模块化的概念,如果想利用 Javascript 构建一个大型项目,就会有很多问题。例如 1.命名冲突;2.变量私有;2.依赖关系的管理等问题。
  • 我们所知道的一些模块规范有 AMD、CMD、UMD、CommonJS 。CommonJS 用于服务器,AMD 用于浏览器。目前比较主流的有 UMD、CommonJS。
  • CommonJS 模块系统是同步加载的.
  • node 使用的模块化系统就是基于 CommonJS 规范的。反言之,我们讲的大部分的 CommonJS 规范都是基于node的模块。
  • requirejs 是 AMD 规范的一种实现.
  • UMD规范是 AMD + CommonJS + Global Variable 的风格组合产物。有了UMD之后,我们的代码就可以在 node 和浏览器上同时运行了。

CommonJS 语法 (运行时)

// 导出 export.js  不显式地导出时,默认是一个空对象就相当于下面的代码
module.exports = {}
// 单独导出
module.exports.name = 'export'
module.exports.age = 123456
exports.height = '300'
// 整体导出,整体导出时不可以使用 exports, exports 本身是 module.exports 的一个引用,在赋值之后即失去了当前的引用而成为了模块中的一个变量了。
module.exports = { name: 'export', age: 123456, height: '300' }
exports = { name: 'export', age: 123456, height: '300' } // 这样写是错误的

// 导入
const $obj = require('./export')
$obj.name

ESM (编译时)

  • ESM 是 es6 推出的 javascript 模块规范。在这之前由于没有规范,所以社区推出了 CommonJS 规范、 require.js 等。
  • ESM 的语法是静态的、导出是绑定的。
  • 静态的语法意味着可以在编译时确定导入和导出,更加快速的查找依赖,可以使用lint工具对模块依赖进行检查,可以对导入导出加上类型信息进行静态的类型检查。
  • 在标签中引入模块:<script type="module" src="..."></script>
// 导出 foo.js
// 默认导出

// 导入 main.js
import height, { Person, age, name as bname, sum } from "./foo.js"
export const name = "why";
export const age = 18;
export function sum(a, b) {
  return a + b;
}
export class Person {
  constructor(name) {
    this.name = name;
  }
}

const aaa = 'aaa'
export { aaa as baaa} // 导出方式二:整体导出,起别名
export default aaa

// 导入导出
export { age, sum } from "./foo.js"
export * from "./foo.js"

// 动态加载
import('./foo.js').then(foo => {
  console.log(foo.sum)
})

浏览器异步加载

<script src="xxx.js" defer></script>
<script src="xxx.js" async></script>
  • defer要等到整个页面在内存中正常渲染结束(DOM 结构完全生成,以及其他脚本执行完成),才会执行;
  • async一旦下载完,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染。
<script type="module" src="./foo.js"></script>
<!-- 等同于 -->
<script type="module" src="./foo.js" defer></script>