CommonJS规范的提出主要是弥补JavaScript没有标准的缺陷,以达到开发大型应用的基础能力。
昨天说到了nodejs,简单的谈了谈nodejs是个啥,今天就来看一看node中的模块化机制,从js这门语言诞生以来,一直给人的感觉就是简单也就是做做特效、表单验证啥的。其实我在学校也经常听到这样的言论,为此还和室友干了一架(题外话,这就不谈了)。现在的js已经不是局限在当初的那个时代了,现在js负责的也越来越多,我们急切的需要一种规范,来让js大展拳脚。
一、CommonJS出现解决了什么问题
朴灵老师在书中也是提到了几点js规范上的缺陷。
1.没有模块系统
不知道大家以前接触过Java或者Python没有,我们可以在文件与文件之间,十分方便的去引用导出我们需要的东西。然后很凄惨的回过头看看我们的js,以前是没有模块这个概念的,以前js只是做表单验证啥的没觉得什么,当我们的项目越来越大,项目越来越难以维护,这时候我们就急需要一种模块机制。
2.标准库很少
ECMAScript(有没有人不知道这是啥,我觉得应该大家都知道)定义的核心库是非常少的,没有像java那样对文件系统、网络、I/O流的标准库,这些在我们开发大型应用时是很常见的需求,但是js中是没有的。
3.没有标准接口
我们在js中没有见到过如数据库、web服务器等等的标准统一接口,这也是十分的不方便的。
4.缺乏包管理系统
好吧,其实我以前就一直想吐槽这一点,我以前有问题去问同学的时候,他们统一的回答是,你去导个包啊,这时候我就很想去怼他一句。没有包管理的系统,我们就不能去很方便的自动加载,安装依赖,去使用别人写好的包文件。
CommonJS为js开发指明了一条大道,规范里面涵盖了模块、二进制、I/O流、包管理、进程环境等等。Node借鉴CommonJS的Modules规范实现了一套很容易的模块系统,而另一个伟大的创造NPM对包管理规范的实现也使得我们在开发的时候事半功倍。
二、CommonJS的模块规范
1. 模块定义
在模块中,提供了exports对象用来导出当前模块的变量或者是方法。同时在模块中还存在一个module对象,它代表的是当前模块自身,exports呢是module的一个属性,在Node中一个文件就是一个模块,都有自己的作用域,关于exports和module.exports的关系与区别下面再谈。
// a.js
exports.a = 1;2. 模块标识
模块标识就是传给require方法的参数,必须是符合小驼峰命名的字符串,或者绝对相对路径。
3. 模块引入
模块的导入也非常简单,在模块中存在一个require()方法,这个方法接收模块标识,就可以引入一个模块了。
// b.js
const { a } = require('./a'); // 1三、Node中的模块
我们先来看一段代码。
然后我们把他跑起来,我们到浏览器里去看。
在浏览器里我们看到了这样的一幕,很奇怪是不是,我们明明没有写这么多代码。原来Nodejs悄悄地帮我们做了这项工作,在我们代码的头和尾加上了这些代码。我们再来看一看,函数里面传入的几个参数是什么?里面的require就不用多说了,这是用来引入的,而 __filename 和 __ dirname顾名思义就是指这个模块的文件路径和文件夹路径,下面我们就来看一看exports和module.exports。
exports和module.exports
可以看到当我们执行完代码后,exports和module.exports上都挂载了一个log方法,也就是我们导出去的方法。敲重点了,exports是module.exports的引用,好了这么说大家应该就明白了,整个模块唯一的出口就是module.exports,而exports是给我们提供的一个简便的写法,但是呢如果我们改变了exports的指向,也就是重新给他赋值了,那么他就不会再有导出的功能了。
四、require规则
其实对于require的规则,也是有几点要提的。
- /代表绝对路径,./代表相对路径
- 默认的扩展名是js,如果你不写的话会按照.js、.json、.node去尝试。
- 如果你引入的时候没有写路径的话,会先去内建模块去找,比如说http等,然后就回去node_modules里去找,层层的往上一级的node_modules找,直到根路径。
- 还有node对于模块是有缓存的,你加载了第一次之后,第二次开始就会在缓存中找到,缓存的优先级是大于内建模块的,是优先级最高的。
感觉内容有点多,今天看的比较草,望多多包涵,多提宝贵意见,谢谢。