前面几篇播客使用过内置fs模块,http模块, 而这些模块都不是我们写的, 都是直接拿过来使用, 那么我们能不能自己写一个模块, 应该怎么写, 有哪些规矩, 如果我们自己写了一个模块, 能不能提供给其他编程人员直接使用, 应该怎么用?
Electron 跨平台的桌面应用框架: https://electronjs.org/
CommonJS规范的由来
JS 的表现的表现能力取决于宿主环境提供的API, 在web1.0 时代, W3C 组织提供了浏览器的规范支持, 在web2.0 时代, 随着HTML5的发展, 更多的标准API 出现在了浏览器中, 但是, 在后端 JS 中标准的制定纹丝不动 ;
由 Mozilla 工程师Kevin Dangoor于2009年1月提出名为 ServerJS 的规范; 2009年8月,更名为CommonJS,以显示 API 的更广泛适用性。
我在这里描述的不是技术问题。这是一个人们聚在一起并决定前进并开始建立更大和更冷的东西的问题 --Kevin Dangoor
CommonJS 的模块规范
CommonJS对模块的定义十分简单,主要分为:
1、模块引用:
使用 require()
方法引入一个模块API ;
2、模块定义:
在模块中使用 exports 对象导出当前模块数据或方法;
在模块中还存在一个module对象,它代表模块自身,module对象有一个exports 属性,用于数据导出;
其实exports 对象就是module.exports 的引用; exports === module.exports
3、模块标识:
其实就是模块的文件名,必须符合小驼峰法命名规则,使用require()
引入时使用 . 或 ..
开头的相对路径或`/开头的绝对路径,引入时可以不写文件后缀名;
重点注意 : 模块中的方法和变量的作用于尽在模块内部,每个模块具有独立的空间,互不干扰;
CommonJS 构建的模块机制中的引入与导出是我们完全不用考虑变量污染或者替换的问题。
模块加载的顺序和规则
在 CommonJS 规范中,使用 require()
加载(引入) 模块时,模块标识必须使用相对路径或绝对路径指明模块位置,但是在node的实现中,我们可以不指明模块路径;如: require('fs')、require('moment')
;
如果没有指明路径,那就是加载核心模块或第三方模块,指明加载路径一般就是加载自定义模块;
不管加载什么模块,都是优先从缓存中加载:
Node 加载模块时,如果这个模块已经被加载过了,则会直接缓存起来,将来再次引用时不会再次加载这个模块(即:如果一个模块被加载两次,则模块中的代码只会被执行一次)
而核心模块和第三方模块的的加载顺序就是:
先加载核心模块,核心模块的内容都是在安装node时已经编译好的可执行的二进制代码,加载执行的速度,仅次于缓存加载,如果核心模块中没有,则加载第三方模块
第三方模块的加载规则:
- 先在当前文件的模块所属目录去找 node_modules目录
- 如果找到,则去该目录中找 模块名的目录 如 : moment
- 如果找到 moment 目录, 则找该目录中的 package.json文件
- 如果找到 package.json 文件,则找该文件中的 main属性
- 如果找到main 属性,则拿到该属性对应的文件
- 如果找到 moment 目录之后,
- 没有package.json
- 或者有 package.json 没有 main 属性
- 或者有 main 属性,但是指向的路径不存在
- 则 node 会默认去看一下 moment 目录中有没有 index.js --> index.json--> index.node 文件
- 如果找不到index 或者 找不到 moment 或者找不到 node_modules
- 则进入上一级目录找 node_moudles 查找(规则同上)
- 如果上一级还找不到,继续向上,一直到当前文件所属磁盘的根目录
- 如果到磁盘概目录还没有找到,直接报错
Node对CommonJS的实现 (Node模块化,自定义模块)
model1.js
var a = 1;
function add(value1, value2) {
return value1 + value2;
}
//变量导出
exports.a = a;
//方法导出
exports.add = add;
test.js
//导入当前路径下的自定义模块model1
var model = require('./model1');
console.log(model.a);
console.log(model.add(3,4));
运行结果
以上代码就是自定义模块的基本规则 这是重点
注意:
module.exports 可以直接赋值,值就会被导出
但是exports直接赋值,不能导出; 必须使用exportsd.xx
// module.exports = {name:123};
// exports.data = {};
// module.exports 可以直接赋值,值就会被导出
// 但是exports直接赋值,不能导出; 必须使用exportsd.xx
//还可以使用这种匿名导出,类似于构造方法
// module.exports = function(){
// return 123;
// }
module.exports = {
name:'lisi',
fun:function(){
console.log(123456);
}
}