了解 CommonJs 吗 ? 了解。说说 module.exports 和 exports 有什么区别 ?呃,,这个,,🤔

提到 CommonJs,第一时间其实想到的就是 Node.js 的模块,这种模块化的写法浏览器是不支持的,其实这句话只说对了一半,CommonJs 是一种模块化规范,Node.js 只是实现了这种规范,就比如 Promise A+ 这是一个实现异步的一种规范,JavaScript只是根据这个规范实现了这个功能,它浏览器端和 Node.js z中的实现也是不完全一致,其他语言中也有根据这个规范实现的库。

总的来说,CommonJs 是一种规范,今天来讲讲 Node.js 中的模块化语法,它是一个轻微修改版本的CommonJs(这个描述来自于红宝书第四版),就叫它 Node.js 版本的 CommonJs 吧,其中 module.exports 和 exports 的关联。

话不多说了,直接上例子
js 复制代码
// AModule.js
const foo = () => {
	return Math.random(10);
};

// case 1
module.exports = {
	foo
};
// case 2
module.exports.foo = foo;
// case 3 
exports.foo = foo;
现在我们简单实现一个 foo 函数,然后通过 Node.js 的模块化语法的这三种语法导出。
js 复制代码
// index.js

const AModule = require('./AModule');
console.log(AModule);

// case 1 
// { foo: [Function: foo] }

// case 2
// { foo: [Function: foo] }

// case 3
// { foo: [Function: foo] }
java 复制代码
以上都是比较正确的写法,在 index.js 中都成功获取到 AModule,但是貌似写法不太一样,module.exports 和 exports 傻傻分不清楚,
js 复制代码
// AModule.js

const a = '1';
const foo = () => {
	return Math.random(10);
};

// case 4
exports = {
	foo,
	a
};
// {} 
// 看着就不正常,结果也确实没有获取到

// case 5

exports.foo = foo;
module.exports.a = a;

// { foo: [Function: foo], a: '1' }
// 看似不太正常,但是 foo 和 a 都成功获取到了

// case 6
exports.foo = foo;
module.exports = {}

看完前面 5 个 case,这个 case 6,相信聪明的你,已经知道打印的是什么了,已经明白了这俩玩意有什么区别了。

这个东西看完,我个人觉得这个是和对象的赋值是类似,继续往下瞧。

js 复制代码
let a = 1;
let b = a;
a = 2;
console.log(b); // 1

let c = { name: "lzb" };
let d = c;
c.name = 'lll';
console.log(d.name); // 'lll'
看完这个,可能就又明白了

再看下边的例子
js 复制代码
// AModule.js

// case 1
module.exports = {
	foo
}
// case 2
exports.foo = foo;

// 这两种是肯定生效的
// 从语法的角度上讲,exports. 和 module. 这种语法证明,
// 1. 在这个当前的作用域下,是可以获取到的有 exports 和 module 这个两个变量
// 2. 这两个变量应该都是对象

// so ?
// 那么我们直接 console.log() 一下,让他们亮个相

现在就根据上边的两种 case,分别看一下什么情况;

js 复制代码
// AModule.js case 1
console.log(exports);
// {}
console.log(module);
// {
//   id: '...',
//   path: '...',
//   exports: {},
//   filename: '...',
//   loaded: false,
//   children: [],
//   paths: []
// }

module.exports = {
	foo
}

console.log(exports);
// {}
console.log(module);
// 对于当前影响不重要的使用 ... 省略
// {
//   id: '...',
//   path: '...',
//   exports: { foo: [Function: foo] },
//   filename: '...',
//   loaded: false,
//   children: [],
//   paths: []
// }

这里 module.exports 这个的语法,显然是给 module 的 exports 属性赋值,从这个例子中不难看出,最开始 exports 和 module.exports 都是 {}。 而后来 exports 还是 {}, 但是 module.exports 已经被赋值了,此时 exports 和 module.exports,看似有关联,实际上又发现不出来有什么关联,没有证据啊,你找的是鲁迅,跟我周树人有什关系啊,module.exports 这种语法又是大家最常用的,咱们接着往下看

js 复制代码
// AModule.js case 2
console.log(exports);
// {}
console.log(module);
// {
//   id: '...',
//   path: '...',
//   exports: {},
//   filename: '...',
//   loaded: false,
//   children: [],
//   paths: []
// }

exports.foo = foo;

console.log(exports);
// { foo: [Function: foo] },
console.log(module);
// 对于当前影响不重要的使用 ... 省略
// {
//   id: '...',
//   path: '...',
//   exports: { foo: [Function: foo] },
//   filename: '...',
//   loaded: false,
//   children: [],
//   paths: []
// }

咱们再看一下这种情况,这种写法应该是第二常用的写法,module.exports.foo = foo; 虽然也好使,但是应该很少有人这个么写,开始两者都是 {}, 导出之后,两者都是 { foo: [Function: foo] },现在感觉已经初露端倪了。 大胆想象一下,exports === module.exports 应该是 true,准没错了

js 复制代码
// AModule.js case 1
console.log(exports === module.exports);
// true

module.exports = {
	foo
}

console.log(exports === module.exports);
// false

// AModule.js case 2
console.log(exports === module.exports);
// true

exports.foo = foo;

console.log(exports === module.exports);
// true

这个情况跟我们最开始打印 exports 和 module 的情况如出一辙,由此可以断定,exports 和 module.exports 其实就是 c 和 d 一样, 最开始 exports 的值是指向 module.exports 的引用的。

或者说它俩就是一个引用,exports.foo = foo, 只会改变这个引用的中的值, 而 module.exports = {}, 这种,直接开辟了一个新的引用, 这个 exports 还是指向 module.exports 之前的引用,这个样两者就没有干系了, 所以也就是说,在 AModule.js 的初始化的时候相当于有这样一段代码

js 复制代码
let module = {
	exports: {},
	// ...其他属性
}
let exports = module.exports;

也就是说 exports.a = a, 会更新 module.exports, 最终模块的消费方或者使用方,拿的值是 module.exports 的值

总结:不总结了 评论区帮忙总结一下,我看谁说的对

相关推荐
多多米100534 分钟前
初学Vue(2)
前端·javascript·vue.js
柏箱1 小时前
PHP基本语法总结
开发语言·前端·html·php
新缸中之脑1 小时前
Llama 3.2 安卓手机安装教程
前端·人工智能·算法
hmz8561 小时前
最新网课搜题答案查询小程序源码/题库多接口微信小程序源码+自带流量主
前端·微信小程序·小程序
看到请催我学习1 小时前
内存缓存和硬盘缓存
开发语言·前端·javascript·vue.js·缓存·ecmascript
blaizeer2 小时前
深入理解 CSS 浮动(Float):详尽指南
前端·css
编程老船长2 小时前
网页设计基础 第一讲:软件分类介绍、工具选择与课程概览
前端
编程老船长2 小时前
网页设计基础 第二讲:安装与配置 VSCode 开发工具,创建第一个 HTML 页面
前端
速盾cdn2 小时前
速盾:网页游戏部署高防服务器有什么优势?
服务器·前端·web安全
小白求学12 小时前
CSS浮动
前端·css·css3