CommonJS模块与ES6模块的区别(require和import)
Posted shuaigebie
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CommonJS模块与ES6模块的区别(require和import)相关的知识,希望对你有一定的参考价值。
模块化的不同解决方案
追根溯源,JS这门脚本语言设计伊始就是没有模块化的,所以早期的全局变量容易造成命名冲突。但随着web项目越来越大,JS的代码量也与日俱增,于是社区就自发约定了几种模块化的方案:requirejs遵循AMD,seajs遵循CMD,node的module遵循CommonJS规范,虽然写法上有所不同,都是为了能够间接实现模块化的基础上保持较为一致的代码风格。
随着ES2015的发布,官方标准定义了一种模块化的方案,那就是import、export。可是,标准毕竟是标准,各大浏览器和node终端要实现标准还是有一段距离的,目前来说都2018年了主流浏览器都还没实现,还得依赖转换工具(例如babel)转为ES5的代码之后浏览器才能解析。所以这也就解释了为什么我们的工程化代码中nodeJS遵循的CommonJS规范和ES6的模块化方案并存的现象。
CommonJS
1.CommonJS中使用了require导入模块,module.exports导出模块,而module.exports中可以引用exports导出,这两者有什么区别呢?
//a.js
module.exports = count
//b.js
var result = require("./a")
console.log(result)
//node b.js
//输出 0
//将a.js中改为
module.exports.count =count
//node b.js
//输出 {count:0}
//将a.js中改为
exports.count = count
//node b.js
//输出 {count:0}
//将a.js中改为
exports= count
//node b.js
//输出 {}
上面的代码可以得出结论:module.exports和exports均指向一个空对象,而require导入的模块是module.exports导出的模块(当改变module.exports的指向时,require导入的是count不是{count:0};改变exports指向时,得到{ }对象),
exports只是module.exports中的一个引用(当exports导出时变量,module.exports也会增加对应的变量)
2.当使用require命令加载某个模块时,就会运行整个模块的代码
//a.js
var count = 0 ;
console.log(‘123‘)
module.exports = count
//b.js
var result = require("./a")
console.log(result)
//node b.js
//输出 123 0
3.对于基本数据类型,属于复制。即会被模块缓存。同时,在另一个模块可以对该模块输出的变量重新赋值。
4.对于复杂数据类型,属于浅拷贝。由于两个模块引用的对象指向同一个内存空间,因此对该模块的值做修改时会影响另一个模块。
// a.js
let count = 0;
var add = function () {
count++
}
var obj = {
count:10,
add(){
obj.count++
}
}
module.exports = {add,count,obj};
//b.js
var result = require("./a")
result.add()
console.log(result.count)// 0
result.obj.add()
console.log(result.obj.count)// 11
上述案例可以看出:当导入基本数据类型时,两个模块没有任何关联(改变a中的值对于b没有影响),而当导入复杂数据类型时,改变a中的值,b中的值也同样被修改了;
5.当使用require命令加载同一个模块时,不会再执行该模块,而是取到缓存之中的值。也就是说,CommonJS模块无论加载多少次,都只会在第一次加载时运行一次,以后再加载,就返回第一次运行的结果,除非手动清除系统缓存。
上述代码中,b.js中只被加载了一次
ES6模块规范
不同于CommonJS,ES6使用 export 和 import 来导出、导入模块。export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。import采用的是编译时加载,所以import导入的模块必须放在代码的顶部,模块指向也是指向同一个内存对象,所以当改变内存指向的对象的值时,导入值会随之改变(和require导入复杂类型对象相似)
// test.js
var firstName = ‘Michael‘;
var lastName = ‘Jackson‘;
var year = 1958;
export {firstName, lastName, year};
// demo.js
import { firstName } from ‘./test.js‘
console.log(firstName); // ‘Michael‘
import * as test from ‘./test.js‘
console.log(test); //Module{} 所有内容
import { firstName as key, lastName as value } from ‘./test.js‘
console.log(key + ‘--‘ + value); // Michael--Jackson
export default(导出默认值)
var firstName = ‘Michael‘;
var lastName = ‘Jackson‘;
var year = 1958;
export default { firstName, lastName, year };
// demo.js
import test from ‘./test.js‘
console.log(test); // {firstName: "Michael", lastName: "Jackson", year: 1958}
这里相当于
import { default as test } from ‘./test.js‘
总结
CommonJS模块规范和ES6模块规范可以说是两种不同的概念,其作用类似,只是规范的不同导致了使用的方法以及性能的不同
以上是关于CommonJS模块与ES6模块的区别(require和import)的主要内容,如果未能解决你的问题,请参考以下文章
CommonJS模块与ES6模块的区别(require和import)