CommonJs规范和原理
1 什么是模块化
Nodejs采用了模块化规范,每个文件都具有:
- 文件作用域
- 通信规则
加载 (require)
导出 (exports.name || module.exports =name)
2 CommonJs模块规范
Node采用了CommonJs模块规范,在Node中的js有一个很重要的概念:模块系统
- 模块作用域
- 使用 require 方法加载来模块
- 使用 exports 接口对象来导出模块中的成员
2.1 require加载
语法:
var 自定义变量 = require('模块')
两个作用:
- 执行被加载模块中的代码
- 得到被加载模块中的
exports
导出的接口对象
2.2 导出 exports
- Node中是模块作用域,默认文件中所有的成员只在当前文件模块有效
- 对于希望可以被其他模块访问的成员,我们就需要把这些公开的成员挂载到
exports
接口对象中就可以
导出多个成员
exports.str = 'hello'
exports.fn=function(){
return value;
}
exports.obj={
name:value
}
导出单个成员(拿到的就是:函数、字符串)
module.exports='hello Node.js
以下情况会覆盖
module.exports = 'hello'
// 以这个为准,后者会覆盖前者
module.exports = function(x,y){
return x + y;
}
也可以这样导出多个成员
module.exports = {
add : function(x,y){
return x + y;
},
str : 'hello'
}
2.3 exports 原理解析
- 在 Node 中,每个模块内部都有一个自己的module对象
- module 对象中有一个成员:exports (也是一个对象)
- 如果你需要对外导出成员,只需要把导出的成员挂载到 module.exports 中即可
每次导出的接口成员都通过module.exports.name=value 的方式太麻烦属性太长,Node为了简化操作提供了一个变量exports: exports = module.exports
// 测试 exports = module.exports
console.log(exports === module.exports) => true
// 两者一致,那就说明,我们可以使用任意一方来导出内部成员
- 谁来执行require , 谁就可以用变量接收得到module.exports对象
- 注意:在默认代码的最后 return 的是 module.exports 对象,不是exports,所以 如果给 exports 重新赋值
exports = 'srting'
在导出就不会管用
2.4 require 方法加载规则
语法require('模块标识符')
- 优先从缓存中加载
- 核心模块
- 路径形式的文件模块
- 第三方模块
注意:
我们一个项目有且只有一个 node_modules,放在项目根目录中,这样的话项目中所有的子目录中的代码都可以加载到第三方包不会出现有多个 node_modules
核心模块
* 核心模块的本质也是文件
* 核心模块文件已经被编译到了二进制文件中,我们只需要按照名字来加载
# require('./foo.js')
路径形式的模块
require('./foo.js')
require('../foo.js')
require('d:/xxx/xxx/foo.js')
1. ./ 代表当前目录
2. ../ 上一级目录
3. / 当前文件模块所在的磁盘根路径(几乎不用)
4. d:/目录/foo.js 磁盘根目录(几乎不用)
第三方模块
* require('包名')
* 凡是第三模块都必须通过 npm 来下载
* 使用的时候就通过 require('包名') 的方式进行加载使用
* 不可能有任何一个第三方包和核心模块的名字是一样的
* 既不是核心模块、也不是路径形式的模块,会先找到当前文件所处目录中的 node_modules目录,然后依次往下找:
1. node_modules/jquery
2. node_modules/jquery/package.json 文件
3. node_modules/jquery/package.json 文件中的main属性
4. main属性中就记录了 jquery 的入口模块
5. 最后来加载使用这个第三方包 *实际上最终加载的还是文件
如果最后第三方模块的 package.json 文件不存在或者 main 指定的入口模块也是没有
则 node 会自动找该目录下的 index.js, index.js 会作为一个默认备选项
如果以上所有任何一个条件都不成立,则会进入上一级目录中的 node_modules 目录进行查找,如果上一级还没有,则继续往上上一级查找
如果直到当前磁盘根目录,还找不到,最后报错:
con not find module xxx