在ES6模块化规范诞生之前,JavaScript社区已经尝试提出了AMD、CMD、CommonJS等模块化规范。
但是,这些由社区提出的模块化标准,有一定的差异性和局限性,并不是浏览器与服务器通用的模块化标准。例如:
因此,2015年ES6正式定义了JavaScript模块化标准。
ES6模块化规范是浏览器端与服务器端通用的模块化开发规范。它的出现极大的降低了前端开发者的模块化学习成本,开发者不需再额外学习AMD、CMD或CommonJS等模块化规范。
ES6模块化规范中定义:
ES6 Module会自动采用严格模式,这在ES5中是一个可选项。以前我们可以通过选择是否在文件开始时加上”use strict”来控制严格模式,在ES6 Module中不管开头是否有”use strict”,都会采用严格模式。
node.js中默认仅支持CommonJS模块化规范,如果要使用ES6模块化,需要进行如下两步配置:
ES6的模块化主要包含如下3种用法:
let n1 = 10;
let n2 = 20;
function show(){
}
export default{
n1,
show
}
注意:每个模块中,默认导出export default只允许使用一次,否则会报错。
import m1 from './01_默认导出.js'
console.log(m1)
export let s1 = 'aaa'
export let s2 = 'ccc'
export function say() {}
import { s1, s2, say } from './03.按需导出.js'
console.log(s1)
console.log(s2)
console.log(say)
如果只想单纯地执行某个模块中的代码,并不需要得到模块中向外共享的成员,此时,可以直接导入并执行模块代码。
CommonJS是由JavaScript社区于2009年提出的包含模块、文件、IO、控制台在内的一系列标准。在Node.js的实现中采用了CommonJS标准的一部分,并在其基础上做了一些调整。我们所说的CommonJS模块和Node.js中的实现并不完全一样,现在一般谈到CommonJS其实是Node.js中的版本,而非它的原始定义。
CommonJS最初只为服务端设计,直到有了Browsefify——一个运行在Node.js环境下的模块打包工具,它可以将CommonJS模块打包为浏览器可以运行的单个文件。这意味着客户端的代码也可以遵循CommonJS标准来编写了。
Node.js遵循了CommonJS模块化规范,CommonJS规定了模块的特性和各模块之间如何相互依赖。
CommonJS规定:
Node.js中的模块,根据来源不同,分为了3大类,分别是:
在CommonJS中使用require进行模块导入,使用require()方法,可以加载内置模块、用户自定义模块、第三方模块进行使用。
注意:使用require()方法加载模块时,会执行被加载模块中的代码。使用require(),可以省略.js后缀。
当我们require一个模块时会有两种情况:
模块会有一个module对象用来存放其信息,这个对象中有一个属性loaded用于记录该模块是否被加载过。它的默认值为false,当模块第一次被加载和执行过后会置为true,后面再次加载时检查到module.loaded为true,则不会再次执行模块代码。
在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问,这种模块访问级别的访问限制,叫做模块作用域。
每个.js自定义模块中都有一个module对象,它里面存储了和当前模块有关的信息。
在自定义模块中,可以使用module.exports对象,将模块内的成员共享出去,供外界使用。
外界用require()方法导入自定义模块时,得到的就是module.exports所指向的对象。
注意:使用require()方法导入模块时,导入的结果,永远以module.exports指向的对象为准。
由于module.exports写起来比较复杂,为了简化向外共享成员的代码,Node提供了exports对象。默认情况下,exports和module.exports指向同一个对象。最终共享的结果,还是以module.exports指向的对象为准。
在使用exports时要注意,不要直接给exports赋值,否则会导致其失效。如果exports指向了新的对象,module.exports却仍然是原来的空对象。
注意:导出语句不代表模块的末尾,在module.exports或exports后面的代码依旧会照常执行。