-
commonJS
-
nodeJS即使用commonJS规范开发
-
模块化
- 是一种将系统分离成独立功能的方法,是分而治之的编程思想,每个独立的功能或者业务划分为一个独立的模块,暴露的接口可以被应用程序调用,应用程序无需知道每个模块的具体实现
- 优点
- 模块化可以让每个文件的职责单一,非常有利于代码的维护
- 灵活架构、焦点分离
- 方便模块间组合、分解
- 单个模块调试方便
- 多人可协作,互不干扰
- 可测试性高,可分单元测试
- 缺点
- 系统分层,调用链长
- 模块间通信发送消息耗费性能
-
每一个文件即一个模块,有自己独立作用域,里面的变量函数都是私有的,对其他的文件不可见。
-
// index.js var count = 1; var addCount = function (value) { return value + count; };
-
上面代码中,变量
x
和函数addX
,是当前文件example.js
私有的,其他文件不可见。 -
如果需要多个文件分享变量,则需要定义为
global
对象的属性。 global.flag = true;
-
上面的flag属性可以被所有文件读取,但不建议这样做,会污染全局对象
-
每个模块内部,
module
变量代表当前模块。这个变量是一个对象,它的exports
属性(即module.exports
)是对外的接口。加载某个模块,其实是加载该模块的module.exports
属性。 -
require
方法用于加载模块,我们可以吧一些公共的方法封装在一个单独的模块中,用到的时候直接加载该模块即可 var index = require('./index.js'); console.log(index.count); // 1 console.log(index.addCount(1)); // 2
-
所有代码都运行在模块作用域,不会污染全局作用域
-
模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
-
模块加载的顺序,按照其在代码中出现的顺序。
-
每个模块内部,都有一个
module
对象,代表当前模块。它有以下属性。-
module.id
模块的识别符,通常是带有绝对路径的模块文件名。 -
module.filename
模块的文件名,带有绝对路径。 -
module.loaded
返回一个布尔值,表示模块是否已经完成加载。 -
module.parent
返回一个对象,表示调用该模块的模块。 -
module.children
返回一个数组,表示该模块要用到的其他模块。 -
module.exports
表示模块对外输出的值。
-
-
commonJS主要有三个模块
- require(加载模块或定义模块或模块初始化)
- 每个模块都有一个require函数,接收一个字符串的参数,指向模块的唯一ID(模块名称),用来加载模块
- exports
- 每个模块都有一个exports对象,模块中对外抛出的API则需要绑定在这个对象上,用来抛出模块中需要抛出的API,exports指向module.exports,最终requier的其实是module.exports
- module
- 每个模块都有一个module对象,包含该模块的信息,同时也包含exports对象
- 建议导出对象用module.exports,导出多个方法和变量使用exports
- require(加载模块或定义模块或模块初始化)
-
nodeJS的模块主要分为三种
- 核心模块
- 例如: http、path、fs
- 文件模块
- 例如:本地开发的index.js、test.js等
- 第三方模块
- 例如:express,需要下载使用
- 核心模块
-
模块的加载机制
- CommonJS模块的加载机制是,输入的是被输出的值的拷贝。也就是说,一旦输出一个值,模块内部的变化就影响不到这个值
- 核心模块在Node.js源代码编译的时候编译进了二进制执行文件,在nodejs启动过程中,部分核心模块直接加载进了内存中,所以这部分模块引入时可以省略文件定位和编译执行两个步骤,所以加载的速度最快
- 文件模块是动态加载的,加载速度比核心模块慢。但是Node.js对核心模块和文件模块都进行了缓存,于是在第二次require时,是不会有重复开销的
- process.moduleLoadList可以查看核心模块
-
模块初始化
-
一个模块中的JS代码仅在模块第一次被使用时执行一次,并在执行过程中初始化模块的导出对象。之后,缓存起来的导出对象被重复利用
-
若想让模块不被缓存
delete require.cache[module.filename];
-
-
主模块
- 通过命令行参数传递给NodeJS以启动程序的模块被称为主模块。主模块负责调度组成整个程序的其它模块完成工作。例如通过node main.js命令启动程序时,main.js就是主模块也称为入口文件
-
二进制模块
- nodeJS中也会使用到二进制模块,可以提供一些操作系统的方法和接口,除了后缀名为.node外,使用和js模块无差异
-
模块路径解析规则
-
require函数支持斜杠(/)或盘符(C:)开头的绝对路径,也支持./开头的相对路径。但这两种路径在模块之间建立了强耦合关系,一旦某个模块文件的存放位置需要变更,使用该模块的其它模块的代码也需要跟着调整,变得牵一发动全身。因此,require函数支持第三种形式的路径,写法类似于a/b,并依次按照以下规则解析路径,直到找到模块位置
-
第三种方式需要设置NODE_PATH,NODE_PATH 环境变量中包含一到多个目录路径,路径之间在 Linux 下使用:分隔,在 Windows 下使用;
-
例如:
NODE_PATH=/home/user/lib:/home/lib
-
-
如果传递给 require 函数的是 NodeJS 内置模块名称,不做路径解析,直接返回内部模块的导出对象,例如require('fs')。
-
node_modules
- 依赖的第三方模块的一个集合,使用通过require直接引入,访问其API即可使用
-
-
package(包管理文件)
-
管理依赖模块的文件,和node_modules中的依赖包对应
-
package.json
-
生成npm init
{ "name": "20190624", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" }
-
name 项目名称
-
version 项目版本
-
description 项目描述
-
main 指定入口文件
-
author 作者
-
keyword 关键字
-
license 授权方式
- ISC 开放源代码
-
-
网友评论