提高代码覆盖率,方便进行管理,就有了模块化的规范,目前有 CommonJS、AMD、CMD、ES Module。着重分析一下CommonJS、ES Module

CommonJS (cjs)

使用方法

  1. // 定义模块 c.js
  2. function c () {
  3. console.log('buer')
  4. }
  5. module.exports = {
  6. c
  7. }
  8. // 使用模块
  9. var d = require('./c.js')
  10. d.c()

环境

  • 浏览器
  • [x] Node.js

    原因是浏览器中缺少Node.js重的环境变量

  • module

  • exports
  • require
  • global

    特点(对比ES Module)

  1. CommonJS模块输出的是一个值的复制,ES6模块输出的是值的引用
  2. CommonJS模块是运行时加载,ES6模块是编译时输出接口

    第二个差异是因为CommonJS加载的是一个对象,即module.export属性,该对象只有在脚本运行结束时才会生成。而ES6模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。CommonJS模块输出的是值的复制,一旦输出这个值,模块内部的变化就影响不到这个值。

例如

  1. //lib.js 一个commonJS模块
  2. var counter = 3
  3. function incCounter() {
  4. counter++
  5. }
  6. module.exports = {
  7. counter : counter,
  8. incCounter : incCounter,
  9. }
  10. //main.js 在这个函数里加载这个模块
  11. var mod = require ('./lib')
  12. console.log(mod.counter)
  13. mod.incCounter()
  14. console.log(mod.counter)
  15. // 打印出来都为 3

ES Module

使用方法

  1. // 定义模块 c.js
  2. export let c = function () {
  3. console.log('buer')
  4. }
  5. // 使用模块
  6. import { c } from './c.js
  7. c()

环境

  • 浏览器 (script 标签中需要有属性 type=module
  • Node.js (需要node版本>13.2 并且模块名为 .mjs 或者 package.json 中 type=module

    特点

  1. 浏览器中 script标签 加上 type=module后,会跨域(实际上是JS模块的安全性需要

    Unlike classic scripts, module scripts require the use of the CORS protocol for cross-origin fetching. — MDN

参考 模块化的背景

  1. 对比上面 CommonJS,ES6导出的为模块引用,JS引擎对脚本静态分析的时候,遇到模块加载命令import就会生成一个只读引用。等到脚本真正执行的时候,再根据这个只读引用到被加载的模块中取值。因此,ES6模块是动态引用,并且不会缓存值,模块里的变量绑定其所在的模块。 ```javascript //m1.js export var foo = ‘bar’ setTimeout(()=>foo=’baz’,500) //m2.js import {foo} from ‘./m1.js’ console.log(foo) setTimeout(()=>console.log(foo),500)

bar baz ``` 上面的代码表明,ES6模块不会缓存运行结果,而是动态地去被加载的模块取值,并且变量总是绑定其所在的模块。
由于ES6输入的模块变量只是一个“符号连接”,所以这个变量是只读的,对它重新赋值会报错。也就是多次加载都为统一实例

require.js (AMD规范

很少用到,但是AMD思想值得一提

特点

依赖前置,提前执行(也就是直接加载模块然后执行

sea.js (CMD规范

很少用到,但是CMD思想值得一提

特点

依赖就近,延迟执行(也就是直接加载模块然后执行