CommonJS是一个规范,最初提出来是在浏览器以外的地方使用,并且当时被命名为ServerJS,后来为了 体现它的广泛性,修改为CommonJS,平时我们也会简称为CJS
CommonJS规范规定,每个模块内部,
module
变量代表当前模块。这个变量是一个对象,它的exports
属性(即module.exports
)是对外的接口。加载某个模块,其实是加载该模块的module.exports
属性。
Node中对CommonJs进行了支持和实现,让我们在开发Node过程中更方便的进行模块化开发
- 在Node中每一个Js文件都是一个模块
- 这个模块中包含CommonJs规范核心变量:exports、module.exports、require
先来看下面两个文件,bar.js、main.js
在main.js中想要输出并运行bar.js中的变量和函数,但是在执行的时候首先会因为找不到name这个变量而抛出异常。
因此main.js模块要想用到bar.js中的东西,bar.js这个模块就必须导出自己的内容
exports导出
exports是一个对象,我们可以在这个对象上添加很多属性
bar.js模块中通过 exports 对象导出
const name = "deyang";
const age = 18;
let message = "hello javascript";
function sayHello() {
console.log(message)
}
// 将需要到处的内容,添加到exports对象上
exports.name = name;
exports.age = age;
exports.sayHello = sayHello;
main.js模块中通过 require() 导入
const bar = require("./bar");
console.log(bar.name);
console.log(bar.age);
bar.sayHello();
// 也可以直接将导出对象结构获取变量,但不推荐,使用的时候变量来源不清晰
// const { name, age, sayHello } = require("./bar");
// console.log(name);
// console.log(age);
// sayHello();
此时 main.js模块就能顺利获取bar模块的变量方法。这是因为,Node中实现Commonjs规范的本质是对象的引用赋值
下面附上本人珍贵手图
bar.js中的exports对象 和 main中通过require('./bar') 的返回值其实是同一个对象,所以 bar 对象是exports对象的浅拷贝(引用赋值)
So、What is the module.exports ?
我们在Node中导出东西的时候又是通过 module.exports 导出的
module.exports 和 exports 之间的关系又是什么呢?
维基百科对CommonJs的解释:
- CommonJS中是没有module.exports的概念的;
- 为了实现模块的导出,Node中使用的是Module的类,每一个模块都是Module的一个实例,也就是 module;
- Node中真正用于导出的其实根本不是exports,而是module.exports;
但是为什么 exports 也可以导出呢?
因为Node源码中做了以下操作
modulex.exports = exports;
所以 module对象的export属性 是exports 对象的一个引用,真正导出还是看module.exports的
如果改变module.exports对象会发生什么?结果将是翻天覆地的变化
const name = "deyang";
const age = 18;
let message = "hello javascript";
function sayHello() {
console.log(message)
}
exports.name = name;
exports.age = age;
exports.sayHello = sayHello;
module.exports = {
name: "寒冰射手",
age: 99,
sayHello: function() {
console.log('我可不是个傻瓜')
}
}
module.exports不再引用exports对象了,那么修改export还有意义 ?
此时main.js中导入的内容,以bar.js中module.exports 实际导出的为准。
因此输出的结果如下: