一、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 命令后面,不需要再使用大括号了