学习背景
很早之前,我们在网页中写js逻辑常常都是一个js文件从头写到尾,也很少考虑去分成多个模块。渐渐的随着项目增大,js代码维护就变得异常困难,为了解决这个问题前端模块化应运而生,比如用的比较多的requireJs。在nodejs中也会面临这个问题,所以nodejs也有他的解决方案,就是我们要掌握的CommmonJs规范。
软件工程中,程序功能讲究高内聚低耦合。就是把软件分为各个模块,每个模块集中实现自己功能,减少对其他模块的依赖。在CommonJs规范中,我们通常需要定义一个个模块(module),每个模块有自己独立的功能也拥有独立的作用域,对于其他模块是不可见的。当其他模块需要使用该模块的某个功能或者属性时,就需要该模块主动将此功能和属性暴漏出去(即module.exports)形成公用属性或者接口。其他模块在可以引入我们暴漏的属性或接口(require引用)。通过这种方式我们实现每个模块的高内聚,实现松耦合。
学习目标
在该章节,我们需要掌握模块的定义,如何实现一个高内聚的模块(module)。同时我们也要掌握如何将模块中的开放属性以及功能暴漏出去,让其他模块来引用。
module 模块
通常我们定义一js为个模块为,一个js文件中有个独立的对象module。每个js的module都是不同的对象。我们直接写一行代码,将module的结构打印出来。
// zhangsan.js
const name = "张三"
module.exports.name = name
module.exports.say = () => {
console.log('我的名字是:'+name)
}
console.log(module)
输出的module结构为
Module {
Module {
id: '.',
path: 'c:\\Users\\tw949\\OneDrive\\文档\\写作\\nodejs系列教程\\commonJs',
exports: { name: '张三', say: [Function (anonymous)] },
parent: null,
filename: 'c:\\Users\\tw949\\OneDrive\\文档\\写作\\nodejs系列教程\\commonJs\\demo.js',
loaded: false,
children: [],
paths: [
'c:\\Users\\tw949\\OneDrive\\文档\\写作\\nodejs系列教程\\commonJs\\node_modules',
'c:\\Users\\tw949\\OneDrive\\文档\\写作\\nodejs系列教程\\node_modules',
'c:\\Users\\tw949\\OneDrive\\文档\\写作\\node_modules',
'c:\\Users\\tw949\\OneDrive\\文档\\node_modules',
'c:\\Users\\tw949\\OneDrive\\node_modules',
'c:\\Users\\tw949\\node_modules',
'c:\\Users\\node_modules',
'c:\\node_modules'
]
}
}
-
module.id 模块的识别符,通常是带有绝对路径的模块文件名。
-
module.path 模块js文件的绝对路径
-
module.filename 模块的文件名。
-
module.loaded 返回一个布尔值,表示模块是否已经完成加载。
-
module.parent 返回一个对象,表示调用该模块的模块。
-
module.children 返回一个数组,表示该模块要用到的其他模块。
-
module.exports 表示模块对外暴漏的值。
该属性表示当前模块对外暴漏的数据变量,需要把那个数据和方法暴漏出去的话,就将其赋值到module.export上,其他文件使用require加载该模块,实际上就是读取了该变量的值。
-
paths 模块的搜索路径
exports
js文件内暴漏方法出去一样可以使用这个变量,
// zhangsan.js
const name = "张三"
exports.name = name
exports.say = () => {
console.log(name)
}
实际上module.exports和exports是一个值,不信你可以试试下面代码验证一下,我就不说啥了 =_ =!!
console.log(exports === module.exports)
require 引入模块
commonJs内置了require方法来加载其他模块。通常用法是require(js文件地址)。它的基础功能是加载模块js文件,读取模块暴漏的属性(module.exports)。
// zhangsan.js
const name = "张三"
exports.name = name
exports.say = () => {
console.log('我的名字是:' + name)
}
// index.js
const zhangsan = require('./zhangsan.js')
console.log(zhangsan.name) // name 是我们在zhangsan.js中定义的名字属性
zhangsan.say() //say方法是我们在zhangsan.js中定义的方法
require的结构为
- require.main 对象表示 Node.js 进程启动时加载的入口脚本。这个通常不会太过关注。
- require.cache 模块在需要时缓存在此对象中,再次加载该模块会直接从该缓存对象中取。通过从此对象中删除键值,下一次 require 将重新加载模块。
最后
通过该章节学习,我们要掌握module和require的用法,能够自己定义一个模块并在其他模块中使用
参考文档
【1】 nodejs官方中文文档
【2】 ruanyifeng教程