学了JS并且用过Node.js后,对模块化应该是有所理解和应用了,那么肯定见过以下两种模块导入导出的形式
第一种: ES6 Module
// B.jsfunction show() { console.log('show办法被执行')}export default show// A.jsimport show from './B.js'show() // show办法被执行
第二种: CommonJS
// B.jsfunction show() { console.log('show办法被执行')}module.exports = { show}// A.jsconst bModule = require('./B.js')bModule.show() // show办法被执行
以上两种导入导出办法波及到了两种模块标准,别离是ES6 Module 、CommonJS
本文就来聊聊这两者之间的具体应用与区别
1. CommonJS
CommonJS是2009年由JavaScript社区提出的蕴含了模块化的一个规范,起初被Node.js所采纳并实现,也就是说咱们在Node.js中用到的模块导入导出都是按照CommonJS规范来实现的
1.1 导出
咱们能够把一个文件看成一个模块,每个模块之间是相互独立的,即不会相互影响。当须要应用到某个模块时,只需在文件中将指标模块导入即可
要想被其它模块导入首先须要导出须要向外裸露的变量或办法,在CommonJS中导出的语法有以下两种形式
// B.js// 定义了函数showfunction show() { console.log('show办法被调用')}// 定义了变量countlet count = 3/*-------------- 导出办法 --------------*/// 第一种module.exports = { show, count}// 第二种exports.show = showexports.count = count
上述代码中,两种导出形式是等价的。
第一种导出形式是将须要导出的函数或变量存储到 module.exports
外面,其中 module.exports
本来是一个空对象
第二种导出形式中,exports
在外部其实是指向了 module.exports
,所以当咱们执行 exports.变量
或 exports.函数
时,其实就相当于把变量或函数存储到 module.exports
中
留神: 这里要特别强调的是,在应用第二种导出形式时,不能对exports
进行从新赋值,否则就将module.exports
间接全副笼罩了
1.2 导入
再来看一下CommonJS的导入语法
// A.jsconst bModule = require('./B.js')console.log(bModule.count) // 3bModule.show() // show办法被调用
从上述代码中能够看到,CommonJS是通过 require
办法来导入模块的,其参数为模块文件门路,要特地留神的是,咱们导入模块后接管到的其实是一个对象,也就是 module.exports
的值,咱们能从该对象中获取到所需的变量或函数
另外,比拟特地的是,require
办法还能够接管一个表达式作为参数,代码如下
let fileName = 'B.js'const bModule = require('./' + fileName)
因而,咱们是能够动静的扭转并决定模块的加载导入门路的
2. ES6 Module
如题目名写的,该模块规范是在ES6时才被提出的,尔后JS才具备了模块化这一个性
2.1 导出
在ES6 Module 中,导出用到了关键字 export
,导出的形式也大抵分为两种,别离是命名导出 、默认导出
第一种: 命名导出
// B.js/*-------- 单个变量或函数导出 ----------*/export function show() { console.log('show办法被调用') }export let count = 3/*-------- 批量导出 ----------*/function show() { console.log('show办法被调用') }let count = 3export {show, count}
上述代码分了两种状况,且这两种写法是等价的
第一种是单个的变量或函数导出,只须要间接在结尾应用 export
关键字即可;
第二种状况是批量地把多个变量或函数导出,只须要把它们贮存到一个对象中即可
第二种: 默认导出
// B.jsfunction show() { console.log('show办法被调用') }// 命名导出变量countexport let count = 3// 默认导出函数showexport default show
默认导出是在 export
关键词前面再跟上一个 default
示意导出的该变量或函数是匿名的
留神: 一个模块只能默认导出一次,否则就会报错,具体起因会在前面解说
2.2 导入
ES6 Module 的导入用到的关键字是 import
,具体代码如下
// A.jsimport {show, count} from './B.js'show() // show办法被调用console.log(count) // 3
ES6 Module的导入须要用一对 {}
大括号来接管咱们须要导入的办法或函数
留神: 大括号中的变量或函数名必须与导出时的名称截然不同
那么如果咱们想批改导入的变量或函数的名称,能够通过 as
关键词来命名,代码如下
// A.jsimport {show as print, count as number} from './B.js'print() // show办法被调用console.log(number) // 3
如果咱们要想将所有的变量或函数都导入,能够通过 *
来整体导入,代码如下
import * as bModule from './B.js'bModule.show() // show办法被调用console.log(bModule.count) // 3
*
示意全副的意思,咱们将其全副导入,并赋值给 bModule
,这样咱们就能够通过 bModule
获取想要的变量或对象了
以上所说的都是针对命名导出的变量或函数,那么如何导入一个默认导出的变量或函数呢?
// 将通过 export default 导出的变量导入import print from './B.js'print() // show办法被调用
命名导出的变量都是通过 {}
来接管的,那么去掉 {}
,接管的就是默认导出的变量了,因为导出的变量是匿名的,因而咱们能够随便地起个变量名用于接管
补充: 这里特地提一下,与CommonJS不同,ES6 Module 的导入文件门路是不反对表达式的
3. CommonJS 与 ES6 Module 的区别
这两者的次要区别次要有以下两点:
- 对于模块的依赖,CommonJS是动静的,ES6 Module 是动态的
- CommonJS导入的是值的拷贝,ES6 Module导入的是值的援用
3.1 区别一
对于模块的依赖,何为动静?何为动态?
动静是指对于模块的依赖关系建设在代码执行阶段;
动态是指对于模块的依赖关系建设在代码编译阶段;
上文提到,CommonJS导入时,require
的门路参数是反对表达式的,例如
// A.jslet fileName = 'example.js'const bModule = require('./' + fileName)
因为该门路在代码执行时是能够动静扭转的,所以如果在代码编译阶段就建设各个模块的依赖关系,那么肯定是不精确的,只有在代码运行了当前,才能够真正确认模块的依赖关系,因而说CommonJS是动静的。
那么当初你也应该也晓得为什么 ES6 Module 是动态的了吧
3.2 区别二
为了验证这一点,我筹备用实例来演示一下
首先来验证CommonJS,代码如下
// B.jslet count = 3function change() { count ++ // 变量count + 1 console.log('原count值为:', count); // 打印B.js模块中count的值}module.exports = { count, change}// A.jslet count = require('./B.js').count let change = require('./B.js').changeconsole.log('扭转前:', count); change() // 调用模块B.js中的change办法,将原来的count + 1console.log('扭转后:', count); // 运行A.js文件的后果扭转前:3原count值为:4扭转后:3
在上述代码中咱们能够看到,在 A.js
文件中导入了 B.js
文件中的变量 count
和 函数 change
,因为导入的 count
只是对原有值的一个拷贝,因而只管咱们调用了函数 change
扭转了 B.js
文件中变量 count
的值,也不会影响到 A.js
文件中的变量 count
依据这个后果得出结论:CommonJS导入的变量是对原值的拷贝
接下来再来验证一下ES6 Module,代码如下
// B.jslet count = 3function change() { count ++ // 变量count + 1 console.log(count); // 打印B.js模块中count的值}export {count, change}// A.jsimport {count, change} from './B.js';console.log('扭转前:',count);change() // 调用模块B.js中的change办法,将原来的count + 1console.log('扭转后:', count);// 运行A.js文件的后果扭转前:3原count值为:4扭转后:4
相比拟于CommonJS的后果,ES6 Module导入的变量 count
随着原值的扭转而扭转了
依据这个后果得出结论:ES6 Module导入的变量是对原值的援用
4. The end
本篇文章就到此结束啦,对于CommonJS和ES6 Module,还有一些本文未提及的常识,还是心愿大家深刻理解
关注公众号:前端印象,每日分享一个高质量前端技术文,还能支付丰盛前端材料