Nodejs模块化(组件)学习
模块化指的就是将一个大的功能拆分为一个一个小的模块,通过不同的模块的组合来实现一个大功能。
- 在 node 中一个 js 文件就是一个模块
- 模块内部代码对于外部来说都是不可见的,可以通过两种方式向外部暴露
CommonJS 规范的提出,主要是为了弥补当前 JavaScript 没有标准的缺陷。它的终极目标就是:提供一个类似 Python,Ruby 和 Java 语言的标准库。
Node.js 应用由模块组成,每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。
使用模块化代码更加简洁,维护也更加的方便,复用性也很好,代码可以重复使用。
模块的创建
模块的创建不过就是创建一个js代码罢了
一、创建js文件和对外暴露接口
只暴露一个数据
function add(a,b){
return a+b;
}
function div(a,b) {
return a/b;
}
//1 . 暴露数据
module.exports = add;
暴露多个数据
function add(a,b){
return a+b;
}
function div(a,b) {
return a/b;
}
//1 . 暴露数据
// 多个暴露,要使用对象的形式,所以暴露的是一个对象,不介意直接使用的
module.exports = {
add:add,
div:div
};
注意点:
- module.exports 可以暴露任意类型的数据,一般暴露的都是引用类型的(数组、对象、函数)
- 可以使用 module.exports 暴露多个数据(使用对象的形式)
- exports 也可以暴露数据,不过不能使用
exports = xxx
的形式
exprots.a = a;// 需要这样暴露
exports.b = b;
// 最终返回了一个对象, 就算只复制一次也是一个对象
在默认情况下:
exports = module.exports = {};
默认他们是等于一个空对象的。
所以使用exports.a = xxx;
是在对 对象里面添加属性。
总结一下
怎么说的呢?为什么不能这样设置exports = xxx
,这样设置的结果就是引用的使用空对象{}
。原因如下:
exports = module.exports = {},而且最后返回的是module.exports的内容,
exprots 和 module.exports 都是对一个空对象的引用,那么既然exports = xxx,就意味着它不在指向那个空对象了,所以返回的就是一个空对象,而不是设置的值。
但是使用module.exports = xxx 就可以正确返回,这是应该返回的就是module.exports,与初始的那个空对象没有关系了。
模块的引入
使用 require 引入文件即可
// 引入模块 (不要添加__dirname,但是./ 不能省略)
const add = require('./m1.js');
const {add,div} = require('./m1.js');// 返回值是 暴露出的值,如果是一个对象,我们可以使用解构赋值
这里有几点注意:
- 如果没有加文件后缀,会按照以下顺序后缀加载文件
- .js fs模块同步读取文件编译执行
- .json fs模块同步读取文件,用JSON.parse()解析返回结果,它返回的是一个对象,而且json文件不需要使用暴露。
- .node 这是c/c++编写的扩展文件,通过dlopen()方法编译
- 其他扩展名 会以.js文件载入
- 如果是文件夹则会默认加载该文件夹下 package.json 文件中 main 属性对应的文件(一般是index.js)
- 根据这个查找顺序,如果不是核心模块或者安装的模块,如果文件和文件夹同名,先查找文件再是文件夹。
- 如果 main 属性对应的文件不存在,则自动找 index.js index.json
- 如果是内置模块或者是 npm 安装的模块,直接使用包名字即可(不需要路径,加了说不定还要出错),其实就是引用了那个包的
package.json
里面的main - npm 引入包时,如果当前文件夹下的 node_modules 没有,则会自动向上查找(所以就不要加路径了,要不然无法自动向上找)
require搜索的顺序
当没有以 ‘/’、 ‘./’ 或 ‘…/’ 开头来表示文件时,这个模块必须是一个核心模块或加载自 node_modules 目录。
require执行的步骤
- 获取目标文件的内容
- 执行目标文件的代码,它会自动包目标文件的代码包裹在一个函数内部运行,里面自动声明
exports = module.exports = {}
,所以在这一步,如果模块中有相关的输出比如console.log('123')
,就没没有暴露,那么导入这个文件时也会输出123
。 - 返回
moudule.exports
中的值
需要十分注意:require的目标代码是会运行的。
http服务的代码拆分
我们可以创建服务和监听端口的回调函数分别写到另外一个模块中。
app.js
const http = require('http');
const callback = require('./callback.js');// 可以不加,但是我觉得最好加上后缀
const callbackOK = require('./serverOkCallback.js');
const server = http.createServer(callback);
server.listen(80,callbackOK);
callback.js
module.exports = (request,response) => {
response.end('hhhh');
}
serverOkCallback.js
module.exports = ()=>{
console.log('服务已经开始,端口开始监听');
}
还有更好的,就是把创建服务的代码也放在一个模块里面,端口也写在函数的参数里面。
app.js
module.exports = (prot) => {
const http = require('http');
const callback = require('./callback');
const callbackOK = require('./serverOkCallback');
const server = http.createServer(callback);
server.listen(80, callbackOK);
}
server.js
const server = require('./app.js');
server(80);
简化
导出
module.exports
导入
var res = require('./module.js');