# 模块化规范

一、参考资料:

1、介绍模块化发展的历程 (opens new window)

2、各模块化规范思维导图 (opens new window)

相关问题

1、模块化的作用

抽取公共代码、隔离作用域、依赖管理

2、模块化历史

无模块化(IIFE) -> CommonJS -> AMD -> CMD -> ESModule,特殊UMD

# 0、IIFE

在单独的函数作用域中执行代码,避免冲突

(function(){
   return {
       data:[]
   } 
})(jQuery) //注入对象
1
2
3
4
5

# 1、commonJS

  • 服务器端node,浏览器端webpack|browserfy

  • 文件即模块,模块加载同步:服务器端模块加载是运行时同步加载,浏览器模块加载是提前编译打包处理

  • exports = module.exports输出(不能给exports赋值,导致与module引用断开), require引入

  • 缓存:require值会缓存,通过require引用文件时,会将文件执行一遍后,将结果通过浅克隆的方式,写入全局内存,后续require该路径,直接从内存获取,无需重新执行文件

// a.js
var name = 'morrain'
var age = 18
exports.name = name
exports.getAge = function(){
    return age
}
// b.js
var a = require('a.js')
console.log(a.name) // 'morrain'
a.name = 'rename'
console.log(a.name) // 'morrain'
var b = require('a.js')
console.log(b.name) // 'rename'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • 模块输出是值的拷贝,一但输出,模块内部变化后,无法影响之前的引用,而ESModule是引用拷贝。
// a.js
var name = 'morrain'
var age = 18
exports.name = name
exports.age = age
exports.setAge = function(a){
    age = a
}
// b.js
var a = require('a.js')
console.log(a.age) // 18
a.setAge(19)
console.log(a.age) // 18
1
2
3
4
5
6
7
8
9
10
11
12
13
  • commonJS运行时加载,ESModule编译阶段引用
    • CommonJS在引入时是加载整个模块,生成一个对象,然后再从这个生成的对象上读取方法和属性
    • ESModule不是对象,而是通过export暴露出要输出的代码块,在import时使用静态命令的方法引用制定的输出代码块,并在import语句处执行这个要输出的代码,而不是直接加载整个模块

# 2、AMD

  • AMD(Asynchronous module definition)异步的模块定义,浏览器端运行,所有模块默认都是异步加载

  • 代表requireJS:https://requirejs.org/docs/api.html

  • 使用:定义define、加载require、配置config

// 定义:define(id?, depencies?, factory);
// utils和bar可直接使用
define('foo', ['utils', 'bar'], function(utils, bar) {
  utils.add(1, 2);
  return {
    name: 'foo'
  }
})
//配置模块:可以直接配置依赖路径
require.config({ paths: {
  'jquery': 'https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js'
} });

//加载模块:提前加载
require(['jquery'], function(jquery) {
  // ....
})

//提前加载执行顺序
// RequireJS
define('a', function () {
  console.log('a load')
  return {
    run: function () { console.log('a run') }
  }
})

define('b', function () {
  console.log('b load')
  return {
    run: function () { console.log('b run') }
  }
})

require(['a', 'b'], function (a, b) {
  console.log('main run') // 🔥
  a.run()
  b.run()
})

// a load
// b load
// main run
// a run
// b run
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# 3、CMD

  • 代表seaJS,特点支持动态引入依赖文件,按需加载
  • 整合了commonJS和AMD的特点,浏览器端运行
// 引入require
var fs = require('fs'); //同步
require.async('./module3', function (m3) {}) //异步


// sea.js,按需引入
define('a', function (require, exports, module) {
  console.log('a load')
  exports.run = function () { console.log('a run') }
})

define('b', function (require, exports, module) {
  console.log('b load')
  exports.run = function () { console.log('b run') }
})

define('main', function (require, exports, module) {
  console.log('main run')
  var a = require('a')
  a.run()
  var b = require('b')
  b.run()
})

seajs.use('main')

// main run
// a load
// a run
// b load
// b run
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 4、UMD

兼容commonJS和AMD模块化语法,作为一种 同构(isomorphic) 的模块化解决方案,判断这些模块化规范的特征值,判断出当前究竟在哪种模块化规范的环境下,然后把模块内容用检测出的模块化规范的语法导出。

(function(self, factory) {
 if (typeof module === 'object' && typeof module.exports === 'object') {
 	// 当前环境是 CommonJS 规范环境
 	module.exports = factory();
 } else if (typeof define === 'function' && define.amd) {
 	// 当前环境是 AMD 规范环境
 	define(factory)
 } else {
 	// 什么环境都不是,直接挂在全局对象上
 	self.umdModule = factory();
 }
}(this, function() {
 return function() {
 	return Math.random();
 }
}))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 5、ESModule 规范

  • 服务端和浏览器端通用,ESModule 是由 JS 解释器实现,commonjs和amd是在宿主环境中运行时实现
  • import输入、export输出(export default Module、export default Module)
//export 一个模块只能有一个默认输出
export var firstName = 'scp'
export var lastName = 'scp'
var firstName = 'scp'
var lastName = 'scp'
export {firstName, lastName as b}
export default firstName

//import 无{}为默认, *为模块整体加载
export function crc32(){}
import {crc32} from 'crc32'

export default function crc32(){}
import crc32 from 'crc32'

import * as circle from './circle'
circle.area(4)
circle.circumference(14)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Last Updated: 11/11/2021, 11:04:53 AM