学了 JS 并且用过 Node.js 后,对模块化应该是有所理解和应用了,那么肯定见过以下两种模块导入导出的形式
第一种: ES6 Module
// B.js
function show() {console.log('show 办法被执行')
}
export default show
// A.js
import show from './B.js'
show() // show 办法被执行
第二种: CommonJS
// B.js
function show() {console.log('show 办法被执行')
}
module.exports = {show}
// A.js
const 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
// 定义了函数 show
function show() {console.log('show 办法被调用')
}
// 定义了变量 count
let count = 3
/*-------------- 导出办法 --------------*/
// 第一种
module.exports = {
show,
count
}
// 第二种
exports.show = show
exports.count = count
上述代码中,两种导出形式是等价的。
第一种导出形式是将须要导出的函数或变量存储到 module.exports
外面,其中 module.exports
本来是一个空对象
第二种导出形式中,exports
在外部其实是指向了 module.exports
,所以当咱们执行 exports. 变量
或 exports. 函数
时,其实就相当于把变量或函数存储到 module.exports
中
留神: 这里要特别强调的是,在应用第二种导出形式时,不能对
exports
进行从新赋值,否则就将module.exports
间接全副笼罩了
1.2 导入
再来看一下 CommonJS 的导入语法
// A.js
const bModule = require('./B.js')
console.log(bModule.count) // 3
bModule.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 = 3
export {show, count}
上述代码分了两种状况,且这两种写法是等价的
第一种是单个的变量或函数导出,只须要间接在结尾应用 export
关键字即可;
第二种状况是批量地把多个变量或函数导出,只须要把它们贮存到一个对象中即可
第二种: 默认导出
// B.js
function show() { console.log('show 办法被调用') }
// 命名导出变量 count
export let count = 3
// 默认导出函数 show
export default show
默认导出是在 export
关键词前面再跟上一个 default
示意导出的该变量或函数是匿名的
留神: 一个模块只能默认导出一次,否则就会报错,具体起因会在前面解说
2.2 导入
ES6 Module 的导入用到的关键字是 import
,具体代码如下
// A.js
import {show, count} from './B.js'
show() // show 办法被调用
console.log(count) // 3
ES6 Module 的导入须要用一对 {}
大括号来接管咱们须要导入的办法或函数
留神: 大括号中的变量或函数名必须与导出时的名称截然不同
那么如果咱们想批改导入的变量或函数的名称,能够通过 as
关键词来命名,代码如下
// A.js
import {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.js
let fileName = 'example.js'
const bModule = require('./' + fileName)
因为该门路在代码执行时是能够动静扭转的,所以如果在代码编译阶段就建设各个模块的依赖关系,那么肯定是不精确的,只有在代码运行了当前,才能够真正确认模块的依赖关系,因而说 CommonJS 是动静的。
那么当初你也应该也晓得为什么 ES6 Module 是动态的了吧
3.2 区别二
为了验证这一点,我筹备用实例来演示一下
首先来验证 CommonJS,代码如下
// B.js
let count = 3
function change() {
count ++ // 变量 count + 1
console.log('原 count 值为:', count); // 打印 B.js 模块中 count 的值
}
module.exports = {
count,
change
}
// A.js
let count = require('./B.js').count
let change = require('./B.js').change
console.log('扭转前:', count);
change() // 调用模块 B.js 中的 change 办法,将原来的 count + 1
console.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.js
let count = 3
function change() {
count ++ // 变量 count + 1
console.log(count); // 打印 B.js 模块中 count 的值
}
export {count, change}
// A.js
import {count, change} from './B.js';
console.log('扭转前:',count);
change() // 调用模块 B.js 中的 change 办法,将原来的 count + 1
console.log('扭转后:', count);
// 运行 A.js 文件的后果
扭转前:3
原 count 值为:4
扭转后:4
相比拟于 CommonJS 的后果,ES6 Module 导入的变量 count
随着原值的扭转而扭转了
依据这个后果得出结论:ES6 Module 导入的变量是对原值的援用
4. The end
本篇文章就到此结束啦,对于 CommonJS 和 ES6 Module,还有一些本文未提及的常识,还是心愿大家深刻理解
关注公众号:前端印象,每日分享一个高质量前端技术文,还能支付丰盛前端材料