JS模块化开发规范-AMD、CMD、CommonJs、ESModule

391 阅读3分钟

这些规范的目的都是为了JavaScript的模块化开发,

AMD(Asynchronous Module Definition)[require.js]

特点:实现异步加载依赖模块,并且会提前加载,对于依赖的模块提前执行(依赖前置)。

define(id?, depencies?, factory) 

define('add', ['utils'], function(utils){
    return utils.add(1,2)
})

CMD(Common Module Definition)[sea.js]

特点:实现异步加载依赖模块,对于依赖的模块就近加载(依赖后置)

define('add', function(require, exports, module){
    exports.run = function(){
        return 2
    }
})
define('minus', function(require, exports, module){
    exports.run = function(){ return 3}
})

define('main', function(require, exports, module){
    const add = require('add')
    a.run()
    const minus = require('minus')
    minus.run()
})

seaJs.use('main')

CommonJs

特点:运行时加载,同步加载模块,适用于服务端,node.js遵循该规范

  • 1、对于基本数据类型引用属于值引用,同时,在另一个模块可以对该模块输出的变量重新赋值
  • 2、对于复杂数据类型引用属于地址引用,由于两个模块引用的对象指向同一个内存空间,修改时会影响到另一个模块
  • 3、使用require命令加载模块时,会运行整个模块代码
  • 4、使用require命令加载同一个模块时,不会在执行该模块,而是提取到缓存之中的值。也就是说,CommonJs无论加载多少次,都只会在第一次加载时运行一次,以后再加载,就返回第一次运行的结果,除非主动清除系统缓存。
  • 5、循环加载时,属于加载时执行,即脚本代码在require的时候,就会全部执行,一旦出现某个模块被循环加载,就只输出已经执行部分,还未执行的部分不会输出
// b.js
exports.done = false
let a = require('./a.js')
console.log('b.js:1', a.done)
exports.done = true
console.log('b.js:2', 'end')
// a.js
exports.done = false
let b = require('./b.js')
console.log('a.js:1',b.done)
exports.done = true
console.log('a.js:2', 'end')
// c.js
let a = require('a.js')
let b = require('b.js')
console.log('c.js:1', '执行完毕', a.done, b.done)
node c.js
// b.js:1 false
// b.js:2 执行完毕
// a.js:1 true
// a.js:2 执行完毕
// c.js:1 执行完毕 true true
//----------------------------------------------------



    
    
遇到require('a.js')的时候,去执行a.js。a.js内只执行了exports.done = false随即遇到requrie('b.js'),去执行b.js。执行b.jsexports.done = false,随即也遇到require('a.js')遇到重复引用的就会提取之前运行的值此时提取到exports.done = false
  • 执行c.js,

    • 遇到require('a.js'),此时进入到a.js里执行里面代码,
    • a.js
      • 定义exports.done = false
      • 遇到let b = require('b.js'),此时进入到b.js里执行里面代码
        • b.js
          • 定义exports.done = false
          • 遇到let a = require('a.js')//此时已经加载过一次,直接拿结果,也就是上面定义的exports.done = false,继续执行
          • 打印console.log('b.js:1', a.done)
          • exports.done = true
          • 打印console.log('b.js:2', 'end')
    • 继续执行a.js
      • console.log('a.js:1', b.done)
      • exports.done = true
      • console.log('a.js:2; 'end')
  • 继续执行c.js

    • let b = require('b.js') 此时直接拿结果即可exports.done = true

ESModule

## ESModule
* 1、ES6模块中的值属于【动态只读引用】
* 2、对于只读来说,即不允许修改引入变量的值,import的变量是只读,不论是基本数据类型还是复杂数据类型。当模块遇到import命令时,就会生成一个只读引用。等到脚本真正执行时,在根据这个只读引用,到被加载的那个模块里面去取值。
* 3、对于动态来说,原始值发生变化,import加载的值也会发生变化。不论是基本数据类型还是复杂数据类型。
* 4、循环加载时,es6模块是动态引用。只要两个模块之间存在某个引用,代码就能够执行

```javascript
export const obj = {}
export const add = (a, b) => a+b

import {obj, add} from '...'