浅浅谈一下对CommonJS、AMD、CMD、ES Module的理解

144 阅读3分钟

一、CommonJS

1、大概的意思就是每一个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件是不可见
2、CommonJS规范还规定了,每个模块内部有两个变量可以使用,require和module。
require用来加载某个模块
module代表当前模块是一个对象,保存了当前模块的信息。exports是module上的一个属性,保存了当前模块要导出的接口或者变量,使用require加载的某个获取到的就是那个模块使用exports导出的值

3、exports

 为了方便,Node.js在实现CommonJS规范时,为每个模块提高一个exports的私有变量,指向的是module.exports。

4、require

 require命令的基本功能是,读入并执行一个js文件,然后返回该模块的exports对象,如果没有发现指定模块,会报错。第一次加载某个模块时,Node.js会缓存该模块,以后再加载该模块,就直接从缓存取出改模块的module.exports属性返回了

//a.js
var name ='morrain'
var age =18
module.exports.name=name
module.exports.getAge=function(){
    return age
}
//b.js
var a=require('a.js')
console.log(a.name)//'morrain'
a.name='rename'
var b=require('a.js')
console.log(b.name)//'rename'

 如上所示,第二次require模块A时,并没有重新加载并执行模块A。而是直接返回了第一次require时的结果,也就是模块A的module.exports.

二、AMD

来看看AMD规范的实现

<script src="require.js"></script>
<script src="a.js">

 首先要在html文件中引入require.js工具库,就是这个库提供了定义模块,加载模块等功能。它提供了一个全局的define函数用来定义模块。所以在引入require.js文件中,在引入的其他文件,都可以使用define来定义模块 define(id?,dependencies?,factory)   id:可选参数,用来定义模块的标识,如果没有提供该参数,就使用js文件名对于一个js文件只定义了一个模块时,这个参数是可以省略的。dependencies:可选参数,是一个数组,表示当前模块的依赖,如果没有依赖可以不穿factory:工厂方法,模块初始化要执行的函数或对象,如果为函数,它应该只被执行一次,返回值便是模块要导出的值,如果是对象,此对象应该为模块的输出值 所以模块A可以这么定义

//a.js
define(function(){
    var name='morrain'
    var age =18
    return {
        name,
        getAge:()=>age
    }
})
//b.js
define(['a.js'],function(a){
    var name='lilei'
    var age=15
    console.log(a.name)//morrain
    console.log(a.getAge)//18
    return{
        name,
        getAge:()=>age
    }
})

 ,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在回调函数中,等到加载完成之后,这个回调函数才会运行 通过define方法,将代码定义为模块。当这个模块被require时,它开始加载它依赖的模块,当所有依赖的模块加载完成后,开始执行回调函数,返回值是该模块导出ed值。AMD的意思就是异步模块定义

三、CMD

 Sea.js可以像Commonjs那样同步的形式书写模块代码的秘诀在于:当b.js模块被require时,b.js架加载后,Sea.js会扫描b.js的代码,找到require这个关键字,提取所有的依赖项,然后加载,等到依赖的所有模块加载完成后,执行回调函数,此时再执行到require('a.js')这行代码时,a.js已经加载好在内存中了

四、ES6 Module语法

 任何模块化,都必须考虑的两个问题就是导入依赖和导出接口。Es6 Module 也是如此,模块功能主要由两个命令构成:export 和import 。export 命令用于导出模块的对外接口,import命令用于导入其他模块导出的内容。

//a.js
const name='a'
const age=18
function getAge(){
    return age
}
export default{
    name,
    getAge
}
//b.js
import a from 'a.js'
console.log(name)//a
console.log(age)//18

 显然,一个模块只能有一个默认输出,因此export default 命令只能使用一次,同时可以看到,这时import 命令后面,不需要再使用大括号了