前言
js早期没有模块体系,都是通过script标签引入js代码,当项目越来越大时,会出现一些问题,比如:
- 变量污染,因为js都是顶层作用域
- 当js文件相互依赖时,问题会更复杂,引入顺序出错时,会报很多错
为了解决以上问题,就出现了模块化,nodejs使用commonJs模块化规范;es6使用Es Module模块化规范。
CommonJs 用法
导出
可以通过
module.exports进行单个导出,多个导出,或者混合导出
common.js 文件
// 单个导出
let a = 1
module.exports.a = a
// 同时导出多个
let a = 1
let b = 2
function add(val1,val2){
a = val1
b = val2
return a+b
}
module.exports ={
a, b, add
}
// 混合导出
let a = 1
let b = 2
function add(val1,val2){
a = val1
b = val2
return a+b
}
module.exports ={
b, add
}
module.exports.a = a
导出也可以直接用exports,省略module
let a = 1
exports.a = a
注意
- 导出不可以直接给
exports赋值,因为本质上导出的是module.exports,当给exports重新赋值对象,exports就会指向新的一块内存空间,它与module.exports的连接就断开了。
具体原因可查看: t.zoukankan.com/jianxian-p-…
// 这样导出的内容会是空对象
let a = 1
let b = 2
exports = {
a, b
}
导入
通过
require引入
let commons = require('./commons')
console.log(commons) // {a: 1}
动态导入
因为代码发生在运行时,所以可以动态加载代码
let lists = ["./index.js", "./config.js"]
lists.forEach((url) => require(url)) // 动态导入
值的改变
导出的值是值的拷贝,不可以通过add方法修改common.js文件中的a,b值,但是可以在导入文件中直接改变
let commons = require('./commons')
let result = commons.add(9,0)
console.log('index2===>',result,commons.a, commons.b) // a,b的值并没有发生变化 9 1 2
commons.a = 11
console.log(commons.a) // 这个时候a的值就发生了变化 是 11
注意
多次加载同一个js, js文件只会加载一次, 比如下面 commons只会运行一次
// index1.js
let commons = require('./commons')
// index2.js
let commons = require('./commons')
Es Module 用法
导出
导出分为两种:
export和export default,两者可以同时进行导出,只是引入方式不同
ESmodule.js 文件
// 导出单个
export var a = 4
// 导出多个
var a = 4
var b = 22
function add(val1,val2){
a = val1
b = val2
return val1+val2
}
export {
a, b, add
}
// 或者
export default{
a, b, add
}
导入
如果是
export导出,则用在{}进行引入,引入方式如下
import {a, b, add} from './ESmodule'
add(7,7)
console.log('index1====>', a) // index1===> 7
// 或者
import * as all from './ESmodule'
console.log('index1====>', all.a) // index1===> 4
如果是
export default导出, 则通过自定义变量进行引入,引入方式如下
import esData from './ESmodule'
esData.a = '111'
esData.add(7,7)
console.log('index1====>', esData.a) // index1===>'111'
如果既有
export又有export default导出,则用如下方式导入
// 导出
export var a = 4
var b = 22
function add(val1,val2){
a = val1
b = val2
return val1+val2
}
export default {
b, add
}
// 导入
import esData, {a} from './ESmodule'
console.log(a, esData.b) // 4 22
值的改变
当是export导出
- 导出值是
值引用,并且内部有映射关系,所以 不能在导入文件index.js中直接修改值,否则会报错 - 可以通过导出文件
ESmodule.js的add方法,修改导出文件的变量,只是这样会污染变量
// 导出文件 ESmodule.js
var a = 4
var b = 22
function add(val1,val2){
a = val1
b = val2
return val1+val2
}
export {
a, b, add
}
// 导入文件
import {a, b, add} from './ESmodule'
a = 4 // 不可以直接修改,会报错
add(7,7)
console.log('index1====>', a) // 通过add方法将ESmodule.js中的a的值改变了,这时输出7
当是export default导出
- 导出值是
浅拷贝,所以可以在导入文件index.js中直接修改值 - 但是不能修改导出文件
ESmodule.js的值
//导出文件 ESmodule.js
var a = 4
var b = 22
function add(val1,val2){
a = val1
b = val2
return val1+val2
}
export default{
a, b, add
}
// 导入文件 index.js
import esData from './ESmodule'
esData.a = 4
console.log('index1====>', esData.a) // 可以在导入文件中直接修改值 输出4
add(7,7)
console.log('index1====>', a) // 通过add方法不能将ESmodule.js中的a的值改 输出4
export 和 export default 的区别
- 导出次数不同:
export可以导出多次,export default只能导出一次 - 导入方式不同:
export在导入时要加{ },export default则不需要,并可以起任意名称 - 值的改变不同:
export只能在导出文件中改变值,export default只能在导入文件中改变值
CommonJs 和 Es Module对比
| Es Module | CommonJs | |
|---|---|---|
| 输出方式 | export(输出多个) export default(输出一个) | exports(输出多个) module.exports(输出一个) |
| 加载 | 可以单独加载某个方法(接口) | 加载整个模块,即把所有的接口都加载出来 |
| 加载时机 | 解析阶段生成接口并对外输出 | 运行阶段加载模块 |
| 值的变化 | 输出的是值的引用, 原来模块的值改变,则该加载值也变 | 输出的值是拷贝的, 已经加载的值,会使用缓冲, 即原来模块的值改变,不会影响已经加载的该值 |
| this指向 | 指向undefned | 指向该当前模块 |