一、CommonJs
CommonJS中的导入使用require导入模块时,有下面两种情况(导出:exports和module.exports):
1.require的模块是第一次被加载.这时会首先执行该模块,然后导出内容
2.require的模块曾被加载过.这时该模块的代码不会再次执行,而是直接导出上次执行后的结果
//exports.js
console.log('cal.js')
module.exports = {
name: '我是乔峰',
add: function(a, b) {
return a + b
}
}
//import.js
// 第一次require
const add = require('./export').add
console.log(add(1, 2)) // cal.js 3
// 第二次require
const name = require('./export').name
console.log(name)// 我是乔峰
module.exports和exports的区别(导入:require):
1.exports = module.exports = {};
2.exports是module.exports的一个引用
3.require引用模块后,返回给调用者的是module.exports而不是exports
4.exports.xxx相当于在导出对象上挂属性
5.exports = xxx相当于给exports对象重新赋值(改变了exports的指向,使其指向其他对象),调用模块不能访问exports对象及其属性(所以exports = {a:xxx}或者exports = xxx得到的数据都是{})
6.如果此模块是一个类,就应该直接赋值module.exports,这样调用者就是一个类构造器,可以直接new实例
总结:exports会默认设置为module.exports的快捷方式,可以往里面添加属性( exports.test ),但是不可以修改它的指向,修改了他的指向,他就和普通的对象没有啥差别,因为在common.js里模块对外输出永远是module.exports,如果exports改变了指向之后,就会不在生效。module.exports的优先级会高于exports,module.exports中已经定义好的属性,exports修改不会生效
//export.js
module.exports = {
name:'11',
age:18,
sex:'女'
};
exports.age = 22;
//import.js
let data = require("./export");
console.log("data",data);//{name:'11',age:18,sex:'女'}
require:
1.有时我们加载一个模块,不需要获取其导出的内容,只是想要通过执行它而产生某种作用,比如把它的接口挂载到全局对象上,此时直接使用require即可
require('./task.js')
2.require可以接收表达式,可以动态加载指定的模块
const moduleNames = ['foo.js', 'bar.js']
moduleNames.forEach(name => {
require('./' + name)
})
博客地址:https://blog.51cto.com/u_11871779/2526416
二、.EsModule
导出:单个导出(export)和默认导出(export default):
1.单个导出在导入时不像CommonJs一样直接把值全部导入进来了,Es Module中可以导入我想要的值。那么默认导出就是全部直接导入进来
// export.js
// 导出变量
export const age = 24
// 导出函数也可以
export function fn() {}
export const test = () => {}
// 如果有多个的话
const name = "蛙人"
const sex = "male"
export { name, sex }
// import.js
import { name,age,fn,test,sex } from "./export.js";
console.log('导入的值',name,age,fn,test,sex);// 蛙人 24 [Function: fn] [Function: test] male
2.可以使用export和export default同时使用并且互不影响,只需要在导入时地方注意,如果文件里有混合导入,则必须先导入默认导出的,在导入单个导入的值。
导入
1.Es Module使用的是import语法进行导入。如果要单个导入则必须使用花括号{}
// export.js
export const name = "蛙人"
export const age = 24
// import.js
import { name, age } from './index.js'
console.log(name, age) // "蛙人" 24
// 如果里面全是单个导出,我们就想全部直接导入则可以这样写
import * as all from './index.js'
console.log(all) // {name: "蛙人", age: 24}
2.混合导入,则该文件内用到混合导入,import语句必须先是默认导出,后面再是单个导出,顺序一定要正确否则报错。
3.用export default导出的值,可以任意起别名(它本身没名字)
第一种:
// export.js
export default {
msg: "蛙人"
}
//import.js
import data from './export.js'
console.log('导入的值',data);// { msg: '蛙人' }
第二种:
// export.js
let a = 123
export default a
// import.js
import c from './export.js'
console.log('导入的值',c); // 123
或者
import {default as all} from './export.js'
console.log('导入的值',all); // 123
4.export导出的值是值的引用,并且内部有映射关系,这是export关键字的作用。而且导入的值,不能进行修改也就是只读状态。
// export.js
export let num = 0;
export function add() {
++ num
}
//import.js
import {num,add} from './export.js'
console.log('add前的num',num);//0
add();
console.log('add后的num',num);//1
num = 10 // 报错
注意!!require导入的文件可以不加.js或.ts后缀,但是import导入必须要加!!
三、CommonJs和Es6模块的区别
- CommonJs:
- 对于基本数据类型,属于复制。即会被模块缓存。同时,在另一个模块可以对该模块输出的变量重新赋值。
- 对于复杂数据类型,属于浅拷贝。由于两个模块引用的对象指向同一个内存空间,因此对该模块的值做修改时会影响另一个模块。
- 当使用require命令加载某个模块时,就会运行整个模块的代码。
- 当使用require命令加载同一个模块时,不会再执行该模块,而是取到缓存之中的值。也就是说,CommonJS模块无论加载多少次,都只会在第一次加载时运行一次,以后再加载,就返回第一次运行的结果,除非手动清除系统缓存。
- 循环加载时,属于加载时执行。即脚本代码在require的时候,就会全部执行。一旦出现某个模块被"循环加载",就只输出已经执行的部分,还未执行的部分不会输出。
- Es6模块
- ES6模块中的值属于【动态只读引用】。
- 对于只读来说,即不允许修改引入变量的值,import的变量是只读的,不论是基本数据类型还是复杂数据类型。当模块遇到import命令时,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。
- 对于动态来说,原始值发生变化,import加载的值也会发生变化。不论是基本数据类型还是复杂数据类型。
- 循环加载时,ES6模块是动态引用。只要两个模块之间存在某个引用,代码就能够执行。
- 两者的区别
- CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
- CommonJS 模块的require()是同步加载模块,ES6 模块的import命令是异步加载,有一个独立的模块依赖的解析阶段。
- CommonJS是对模块的浅拷贝,ES6 Module是对模块的引入,即ES6 Module只存只读,不能改变其值,具体点就是指针指向不能变,类似const 。
- import的接口是read-only(只读状态),不能修改其变量值。 即不能修改其变量的指针指向,但可以改变变量内部指针指向。可以对commonJS对重新赋值(改变指针指向),但是对ES6 Module赋值会编译报错。