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 

vite 结合 esprima写一个插件 commonjs_javascript

 在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();

vite 结合 esprima写一个插件 commonjs_javascript_02

 此时 main.js模块就能顺利获取bar模块的变量方法。这是因为,Node中实现Commonjs规范的本质是对象的引用赋值

下面附上本人珍贵手图

vite 结合 esprima写一个插件 commonjs_赋值_03

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 实际导出的为准。



因此输出的结果如下:


vite 结合 esprima写一个插件 commonjs_ecmascript_04