我是靠谱客的博主 俊逸路灯,最近开发中收集的这篇文章主要介绍CommonJs 和 ESModule 的 区别整理,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1. exports 和 module.exports 的区别

  • module.exports 默认值为{}
  • exports 是 module.exports 的引用
  • exports 默认指向 module.exports 的内存空间
  • require() 返回的是 module.exports 而不是 exports
  • 若对 exports 重新赋值,则断开了 exports 对 module.exports 的指向

引用:

  • require 和 import 都可引用
//foo.js
exports.foo="foo"
//等同于
module.exports.foo="foo"
//bar.js
const { foo } = require('./foo.js')
console.log(foo);//'foo'
复制代码
//foo.js
exports={
foo: 'foo'
}
//bar.js
const { foo } = require('./foo.js')
//reuqire 返回的是 module.exports 对象, 默认为 {}
console.log(foo);//undefined
复制代码

2. commonJs 和 esModule 的区别

  • commonJs是被加载的时候运行,esModule是编译的时候运行
  • commonJs输出的是值的浅拷贝,esModule输出值的引用
  • commentJs具有缓存。在第一次被加载时,会完整运行整个文件并输出一个对象,拷贝(浅拷贝)在内存中。下次加载文件时,直接从内存中取值
commonJs 输出值拷贝
/*************** a.js**********************/
let count = 0
exports.count = count; // 输出值的拷贝
exports.add = ()=>{
//这里改变count值,并不会将module.exports对象的count属性值改变
count++;
}
/*************** b.js**********************/
const { count, add } = require('./a.js')
//在支持es6模块的环境下等同于
import { count, add } from './a.js'
console.log(count) //0
add();
console.log(count)//0
复制代码
esModule 输出值引用
/*************** a.js**********************/
export let count = 0;//输出的是值的引用,指向同一块内存
export const add = ()=>{
count++;//此时引用指向的内存值发生改变
}
/*************** b.js**********************/
import { count, add } from './a.js'
console.log(count) //0
add();
console.log(count)//1
复制代码
commonJs 输出的浅拷贝验证
/*************** a.js**********************/
const foo = {
count: 0
}
//module.exports的foo属性为 foo 对象的浅拷贝,指向同一个内存中
exports.foo=foo;
window.setTimeout(()=>{
foo.count += 1
console.log('changed foo')
},1000)
/*************** b.js**********************/
const
{ foo }
= require('./a.js')
console.log('foo', foo);//'foo',{count: 0}
window.setTimeout(()=>{
console.log('after 2s foo', foo);//'after 2s foo ',{count: 1}
}, 2000)
复制代码
commonJs 输出时的危险操作

其实上个栗子中的 const { foo } = require('./a.js') 或者 const foo = require('./a.js').foo 写法是相当危险的。因为commonJs输出的值的拷贝,若后面在a.js中 对foo的内存指向作出改动,则不能及时更新。

我们将上面的栗子做个小改动:

/*************** a.js**********************/
const foo = {
count: 0
}
exports.foo=foo; //此时foo指向 {count: 0}的内存地址
window.setTimeout(()=>{
//改变 foo 的内存指向
exports.foo='haha';
},1000)
/*************** b.js**********************/
const
{ foo }
= require('./a.js'); //拷贝了 foo属性指向 {count: 0} 内存地址的引用
console.log('foo', foo);//'foo',{count: 0}
window.setTimeout(()=>{
//看!并没有改变!
console.log('after 2s foo', foo);//'after 2s foo ',{count: 0}
}, 2000)
复制代码

改进:

/*************** b.js**********************/
const test = require('./a.js');
//test 拷贝了 整个输出对象{foo:{count: 0} }内存地址的引用
//当内存中的属性值发生变化时,可以拿到最新的值,因为指向的是同一片内存
console.log('foo', test.foo);//'foo',{count: 0}
window.setTimeout(()=>{
//保证获取到的是最新的
console.log('after 2s foo', test.foo);//'after 2s foo ','haha'
}, 2000)
复制代码

进阶:

/*************** child.js**********************/
let foo = 1
setTimeout(()=>{
foo=2;
exports.foo= foo
},1000)
exports.foo=foo
/*******************index.js***************************/
var test =require('./child');
console.log(test.foo);// 1
setTimeout(()=>{
console.log(test.foo) // 2
},2000)
复制代码

将child.js中的输出方式做一下改动,结果就变了。

/*************** child.js**********************/
let foo = 1
setTimeout(()=>{
foo=2;
module.exports={foo};//注意:指向新内存 {foo:2}
},1000)
module.exports={foo}; //指向内存 {foo:1}
/*******************index.js***************************/
var test =require('./child');// 浅拷贝,指向的还是{foo:1}的内存,并缓存在内存中
console.log(test.foo);// 1 //从缓存的内存中取值
setTimeout(()=>{
console.log(test.foo) // 1 //从缓存的内存中取值
},2000)
复制代码

3. ES6 模块加载 CommonJS 模块

module.exports 等同于 export default 可以用 import 引入

4. CommonJS 模块加载 ES6 模块

CommonJS 模块加载 ES6 模块,不能使用require命令,而要使用import()函数。

// es.mjs
let foo = { bar: 'my-default' };
export default foo;
// cjs.js
const es_namespace = await import('./es.mjs');
// es_namespace = {
//
get default() {
//
...
//
}
// }
console.log(es_namespace.default);
// { bar:'my-default' }
复制代码

参考链接:

  • 阮大大:es6.ruanyifeng.com/#docs/modul…
  • JS基本数据类型和引用数据类型的区别及深浅拷贝:www.cnblogs.com/c2016c/arti…

最后

以上就是俊逸路灯为你收集整理的CommonJs 和 ESModule 的 区别整理的全部内容,希望文章能够帮你解决CommonJs 和 ESModule 的 区别整理所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(66)

评论列表共有 0 条评论

立即
投稿
返回
顶部