1. 介绍
require/exports 和 import/exoprt 属于两种不同的模块化规范. require/exports 遵循 CommonJS 模块规范, 而 import/exoprt 遵循 ES6 模块规范.
那么怎么理解模块化规范?
模块化规范: 即为javascript提供模块编写 模块依赖 模块运行的方案
CommonJS模块规范
- 出现的时间在2010年左右, 属于是野生规范, 即 JavaScript 社区中的开发者自己草拟的规则,得到了大家的承认或者广泛的应用
- nodejs 使用的就是 CommonJS 规范
ES6模块规范
- 出现的时间是在2015年, 属于是名门正派, 是 TC39 制定的新的 ECMAScript 版本, 即ES6(2015)包含进来的
2. ES model 和 CommonJS model 使用(node环境)
2.1 CommonJS
let a = 1
let b = 1
function add(a, b) {
return a + b
}
module.exports = {
a,
b,
add
}
let obj = require("./a")
console.log(obj);
console.log(obj.a);
console.log(obj.b);
console.log(obj.add);
2.2 ES6
注意: CommonJS 模块是 Node.js 专用的,与 ES6 模块不兼容. 如果想要在node环境下执行import/export, 需要采用xxx.mjs的后缀名
export const aaa = 'aaa'
export const bbb = 'bbb'
export const ccc = 'ccc'
const str = 'hello es module'
export default str
import { aaa , bbb, ccc } from "./a.mjs"
console.log(aaa);
console.log(ccc);
console.log(str);
3. ES model 和 CommonJS model 区别
3-1. ES6 模块输出的是值的引用,CommonJS 模块输出的是值的拷贝。
3-1-1. ES6 ? 值的引用
解释一下, CommonJS 是值的拷贝(浅拷贝),怎么理解, 可以理解为 ? 输出一个值, 如果模块内部这个值改变,输出的值不会受影响, 看下面代码
var num = 1
function add() {
num++
}
module.exports = {
num,
add,
}
let obj = require("./a")
console.log(obj.num);
obj.add()
console.log(obj.num);
可以看到当我执行obj.add()之后,在打印obj.num,发现这个值并没有改变. 为什么呢? 这是因为mod.counter是一个原始类型的值,会被缓存。除非写成一个函数,才能得到内部变动后的值。
3-1-2. CommonJS ? 值的拷贝
ES module 运行机制和 Commonjs 不一样, 预编译的时候如果读到了 import, 那么就会生成一个只读的引用, 再根据这个引用去对应模块取值. 意思就是原始值变了, import加载的值也会跟这边, 因此,ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块
export var num = 1
export function add() {
num++
}
import { num , add } from "./a.mjs"
console.log(num);
add()
console.log(num);
3-2. CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
因为 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成
let _fs = require('fs')
let stat = _fs.stat
let exists = _fs.exists
let readfile = _fs.readfile
import { stat, exists, readfile } from 'fs'
3-3. CommonJS 模块的require()是同步加载模块,ES6 模块的import命令是异步加载,有一个独立的模块依赖的解析阶段。
commonjs
const A = require('./a')
console.log('index.js执行');
console.log('a.js执行')
const foo = () => {
console.log(require('./b').c);
}
foo()
module.exports = {
foo
}
console.log('b.js执行');
const c = 3
module.exports = {
c
}
es
import { foo } from "./a.mjs"
console.log('index.js执行');
console.log('a.mjs执行')
export const foo = () => {
import('./b.mjs').then(({c}) => {
console.log(c);
})
}
foo()
console.log('b.mjs运行');
export const c = 3
可以看出来: import()是异步加载的,因为index.js在前面打印了,而不是在最后打印,代表他没有被阻塞
3-4. 变量提升
es6
console.log('我是a.mjs内容');
import { num } from './b.mjs'
console.log(num);
console.log('我是b.mjs内容');
export let num = 100
commonjs
console.log('我是a.js内容');
let obj = require('./b')
console.log(obj.num);
console.log('我是b.js内容');
let num = 100
module.exports = {
num
}
可以看到es6现打印了b.js内容, 而connonjs现打印了a.js的内容, 在es6模块中,当预解析a.js时候,发现import,就会去加载b.js. 整个流程就是预编译a.js ? 发现import ? 预解析b.js ? 执行b.js ? 执行a.js
4. 总结
1. ES module是值的引用 CommonJS module是值的拷贝
2. CommonJS 模块是运行时加载,ES6 模块是编译时加载。
3. CommonJS 模块是同步加载,ES6 模块是异步加载,
5. 结语
如果这篇文章帮到了你,欢迎点赞👍和关注??。 文章如有错误之处,希望在评论区指正🙏🙏。
|