JavaScript代码模块化,commonjs如何编写并引用?
发布于 作者:苏南大叔 来源:程序如此灵动~
在JavaScript代码模块化过程中,commonjs是其中一个产物。根据最初的设计,commonjs是适用于服务器(node)端使用的,类似的概念还有AMD/CMD/es6 module。但是,由于webpack提供的兼容方式的存在,commonjs的写法,实际上也可以用于前端页面里面。

本文测试环境:chrome@89.0.4389.114,webpack@5.36.2,node@14.16.0。主要讲述commonjs的基本写法,主要结论是:commonjs写法简单,但是并不是太好用,而且存在着一些大的问题。
模块化的基本概念
JavaScript模块化基本概念就是:一个文件就是一个模块,有自己的作用域。这个文件里面定义的变量、类、函数等,对于别的文件来说,都是不可见的。除非本文件主动使用导出操作,使得这些方法类变量之类的在外部可见。
苏南大叔理解着就是:对每个文件施加了一个隐藏的闭包环境,起到了一个隔绝的作用。写法上非常像class类,似乎就是class里面的public的字样(概念)换成了exports字样(概念),你细品。

commonjs所有代码都运行在模块作用域,不会污染全局作用域。模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。
commonjs的基本写法
和普通的传统函数式编程js相比较的话,其实就是在代码的最末端加上了module.exports字样,其它的地方基本上没有变化。代码类似如下:
var name = 'sunan'
var age = 18
module.exports.name = name
module.exports.getAge = function(){
return age
}或者:
var name = 'sunan'
var age = 18
module.exports={
name:name,
getAge:function(){
return age;
}
}
这里需要特殊说明的是:
- 理论上来说,上面的
module.exports可以缩写成exports,但是并不建议这么使用,因为个别情况下会有问题。 - 另外,在
commonjs模块化方案里面,module就是关键字了,不能被改写。你懂的。
一种简写方式
下面是一个更加简单的写法:
var name = "苏南";
var age = 18;
var getAge = function () {
return age;
}
function setAge(a) {
age = a;
}
module.exports = {
name, age, getAge, setAge
}这里导出的对象的key和内部的变量名是一致的,就可以这样简写:
module.exports = {
name, age, getAge, setAge
}而不是:
module.exports = {
name:name,
age:age,
getAge:getAge,
setAge:setAge
}
基本使用方法(前后端)
这里需要额外说明的是:commonjs在设计的最开始,就是要提供给node类似的后端环境使用的,并不是提供给传统的网页换的。但是,这些commonjs如果通过webpack处理过的话,这些写法在前端也是一样可以使用的。所以,webpack有识别commonjs的能力。
被模块化的代码写法,如上所示。在其他的地方,进行引用的时候,使用require进行操作,如下所示:
var example = require('./example.js');
var example2 = require('./example2');
webpack额外加工(纯浏览器环境)
在node下面直接使用的话,是可以直接识别commonjs的写法的。但是,在纯浏览器环境下使用的话,就恰恰需要编译处理一下才能识别这种commonjs的写法。而webpack恰恰就提供了这种能力,当然,相信其他的打包软件,也会提供类似的能力,这个并非webpack的专利。
这里就简单说说webpack如何处理commonjs。此处测试环境,使用的是:webpack@5.36.2。
其实特别简单,直接npx webpack试试(话说npx是个好命令):
npm install -D webpack webpack-cli
npx webpack配置webpack.config.js(其实没有任何的特殊配置,就是传统的设置entry和output):
var path = require("path");
module.exports = {
entry: path.join(__dirname, 'main.js'),
output: {
path: __dirname,
filename: 'main_4_web.js'
},
};在这个例子里面,main.js里面,使用require加载了module.js。而module.js就是使用了commonjs标准,利用module.exports导出的一个模块文件。

存在问题
commonjs写法真的是非常简单,但是,这种写法也存在着天然的缺陷。这里先进行简要的说明:
- 缺陷一:
module.exports和exports,理论上,两者可以相互替代。但是,建议统一使用module.exports。 - 缺陷二:
commonjs模块会缓存结果,多次调研的话,是会读取缓存文件。这个问题非常严重,严重违背认知。这个问题在后面的文章里面,苏南大叔会对其进行详细阐述。
相关文章
总结
这里总结一下,commonjs写法和使用方法是非常简单的,默认是用于后端使用的。如果在纯浏览器环境下使用,需要进行编译。commonjs存在着一些天生的缺陷,所以需要写代码的时候,特别注意。
更多commonjs的经验文章,请点击苏南大叔的博客: