跳至主要內容

初识node.js

Weipeng Qiao大约 9 分钟

node 中文网open in new window

模块化

认识模块化

node-exportsopen in new window

什么是模块化

  • 模块化是指解决一个复杂问题时,自顶向下逐层把系统划分成若干模块的过程。对于整个系统来说,模块是可组合、分解和更换的单元。

编程领域中的模块化

  • 编程领域中的模块化,就是遵守固定的规则,把一个大文件拆成独立并互相依赖的多个小模块。

  • 把代码进行模块化拆分的好处:

    1. 提高了代码的复用性
    2. 提高了代码的可维护性
    3. 可以实现按需加载

模块化规范

  • 模块化规范就是对代码进行模块化的拆分与组合时,需要遵守的那些规侧。

例如:

  1. 使用什么样的语法格式来引用模块

  2. 在模块中使用什么样的语法格式向外暴露成员

模块化规范的好处:大家都遵守同样的模块化规范写代码,降低了沟通的成本,极大方便了各个模块之间的相互调用,利人利己。

node 中的模块化

node 中模块的分类

Node.js 中根据模块来源的不同,将模块分为了 3 大类,分别是:

  1. 内置模块(内置模块是由 Node.js 官方提供的,例如 fs、path、http 等)
  2. 自定义模块(用户创建的每个 js 文件,都是自定义模块)
  3. 第三方模块(由第三方开发出来的模块,并非官方提供的内置模块,也不是用户创建的自定义模块,使用前需要先下载)

node 中的模块化规范

Node.js 遵循了 CommonJS 模块化规范,CommonJS 规定了模块的特性和各模块之间如何相互依赖。

CommonJS 规定:

  1. 每个模块内部,module变量代表当前模块。
  2. module 变量是一个对象,它的exports属性(即 module.exports)是对外的接口。
  3. 加载某个模块,其实是加载该模块的module.exports属性
  4. require()方法用于加载模块
加载模块

使用强大的require( )方法,可以加载需要的内置模块、用户自定义模块、第三方模块进行使用。

// 加载内置模块
const HTTP = require("http");
// 加载自定义模块
const TEST = require("./test");
// 加载三方模块 (三方模块使用前先要下载)
const MOMENT = require("moment");

注意:使用 require()方法加载其它模块时,会执行被加载模块中的代码。

模块作用域

什么是模块作用域

和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问,这种模块级别的访问限制,叫做模块作用域。

let userName = "张三";
let sayHi = function () {
  console.log("Hi");
};

// 在另一个文件中

const TEST = require("./test");
console.log(TEST); // { }
// 在当前模块中,无法访问到test中的私有成员

模块作用域的好处

防止全部变量污染的问题

<!-- 模块a  -->
<script>
  var userName = "张三";
</script>
<!-- 模块b -->
<script>
  var userName = "李四";
</script>
<script>
  console.log(userName); // 李四
</script>
module 对象

在每个.js自定义模块中都有一个module对象,它里面存储了和当前模块有关的信息,打印如下:

Snipaste_2023-04-07_13-34-15
Snipaste_2023-04-07_13-34-15
module.exports 对象
  • 在自定义模块中,可以使用module.exports对象,将模块内的成员共享出去,供外界使用。

  • 外界用require()方法导入自定义模块时,得到的就是 module.exports 所指向的对象。

exports 对象
  • 由于module.exports单词写起来比较复杂,为了简化向外共享成员的代码,Node 提供了 exports 对象。
  • 默认情况下,exports和module.exports指向同一个对象。最终共享的结果,还是以 module.exports 指向的对象为准。

注意:

  1. 使用 require()方法导入模块时,导入的结果,永远以 module.exports 指向的对象为准。

  2. 为了防止混乱,建议大家不要在同一个模块中同时使用 exports 和 module.exports

http://dev.nodejs.cn/learn/expose-functionality-from-a-nodejs-file-using-exportsopen in new window

可以通过两种方式进行操作。

第一种方式是将对象赋值给 module.exports(这是模块系统提供的对象),这会使文件只导出该对象:

const car = { brand: "Ford", model: "Fiesta" };
module.exports = car;
//在另一个文件中
const car = require("./car");

第二种方式是将要导出的对象添加为 exports 的属性。这种方式可以导出多个对象、函数或数据:

const car = { brand: "Ford", model: "Fiesta" };
exports.car = car;

或直接

exports.car = {
  brand: "Ford",
  model: "Fiesta",
};

module.exports 和 export 之间有什么区别?

前者公开了它指向的对象。 后者公开了它指向的对象的属性。

模块的加载机制

  • 优先从缓存中加载。

  • 模块在第一次加载后会被缓存。这也意味着多次调用 require()不会导致模块的代码被执行多次。

注意:不论是内置模块、用户自定义模块、还是第三方模块,它们都会优先从缓存中加载,从而提高模块的加载效率。

内置模块的加载机制
  • 内置模块是由 Node.js 官方提供的模块,内置模块的加载优先级最高。

例如,require('fs')始终返回内置的 fs 模块,即使在 node _modules 目录下有名字相同的包也叫做 fs。

自定义模块的加载机制
  • 使用 require( )加载自定义模块时,必须指定以./或../开头的路径标识符。在加载自定义模块时,如果没有指定./或../这样的路径标识符,则 node 会把它当作内置模块或第三方模块进行加载。

  • 同时,在使用 require( )导入自定义模块时,如果省略了文件的扩展名,则 Node.js 会按顺序分别尝试加载以下的文件

  1. 按照确切的文件名进行加载
  2. 补全.js扩展名进行加载
  3. 补全.json扩展名进行加载
  4. 补全.node扩展名进行加载
  5. 加载失败,终端报错
第三方模块的加载机制
  • 如果传递给 require()的模块标识符不是一个内置模块,也没有以'./'或'../'开头,则 Node.js 会从当前模块的父目录开始,尝试从/node_modules 文件夹中加载第三方模块。
  • 如果没有找到对应的第三方模块,则移动到再上一层父目录中,进行加载,直到文件系统的根目录。

node 中如何使用 ES6 的模块化?

http://www.ruanyifeng.com/blog/2020/08/how-nodejs-use-es6-module.htmlopen in new window

ES6 模块和 CommonJS 模块有很大的差异。

语法上面,CommonJS 模块使用require()加载和module.exports输出,ES6 模块使用import和export。

用法上面,require()是同步加载,后面的代码必须等待这个命令执行完,才会执行。import命令则是异步加载,或者更准确地说,ES6 模块有一个独立的静态解析阶段,依赖关系的分析是在那个阶段完成的,最底层的模块第一个执行。

Node.js 要求 ES6 模块采用.mjs后缀文件名。也就是说,只要脚本文件里面使用import或者export命令,那么就必须采用.mjs后缀名。Node.js 遇到.mjs文件,就认为它是 ES6 模块,默认启用严格模式,不必在每个模块文件顶部指定"use strict"。

如果不希望将后缀名改成.mjs,可以在项目的package.json文件中,指定type字段为module。

如果这时还要使用 CommonJS 模块,那么需要将 CommonJS 脚本的后缀名都改成.cjs。如果没有type字段,或者type字段为commonjs,则.js脚本会被解释成 CommonJS 模块。

总结为一句话:.mjs文件总是以 ES6 模块加载,.cjs文件总是以 CommonJS 模块加载,.js文件的加载取决于package.json里面type字段的设置。

注意,ES6 模块与 CommonJS 模块尽量不要混用。require命令不能加载.mjs文件,会报错,只有import命令才可以加载.mjs文件。反过来,.mjs文件里面也不能使用require命令,必须使用import。

node 配置环境变量

img1680779723799
img1680779723799

将node_global文件夹的绝对路径添加到 path 环境变量中

终端命令

↑键快速定位到上一次执行的命令
Tab键能够快速补全路径
Esc键清空当前已输入的命令
cls命令清空终端

如何快速切换node版本

可以使用如下工具切换:

n

n:n 是 npm 中的一个包,用来切换 node 版本,需要使用 n,就必须要下载 node 环境

npm-nopen in new window

# 全局安装
npm install -g n

# 查看n的版本
n --version

# 查看可供下载的所有node版本,回车后将会显示所有的node版本,使用上下键,来选择node版本,然后回车即可
n

# 下载最新的node版本
n latest

# 删除指定的node版本
n rm <version>

# 使用对应的node版本
n <version>

nvm

https://github.com/nvm-sh/nvmopen in new window

nvm 是一个单独的软件,需要下载,不需要 node 环境,如已经安装 node,需要卸载,以及环境变量,和全局包。

只能 mac 使用

nvm-window

https://github.com/coreybutler/nvm-windowsopen in new window

nvm-window 和 nvm 功能一样,但是并不是 nvm 的 window 版本,是由其他人开发的供 window 使用的 node 版本管理工具。

安装前须知

  1. 安装路径上不要有中文字符或者空格,否则会出现错误
  2. 如已经安装 node,需要卸载,以及环境变量,和全局包。

​ 下载.exe结尾的文件来安装,一般安装完成会自动配置环境变量

# 列出 Node.js 的安装目录,默认是 NVM 的安装目录
nvm root
# 设置 Node.js 的安装目录;
nvm root <path>
# 列出已经安装的 Node.js 的版本号,正在使用的版本前标有星号
nvm list
# 列出所有可以安装的 Node.js 的版本
nvm list available
# 安装指定版本的 Node.js
nvm install <version>
# 安装最新的 LTS(稳定版) 版的 Node.js
nvm install lts
# 安装最新版的 Node.js
nvm install latest
# 卸载指定版本的 Node.js
nvm uninstall <version>:
# 使用指定版本的 Node.js
nvm use <version>
#使用最新的 LTS 版的 Node.js,要是没安装就无法用
nvm use lts
#使用最新版的 Node.js,要是没安装就无法用
nvm use latest
#使用最新安装的 Node.js;
nvm use newest 使用最新安装的 Node.js;
# 列出当前使用的 Node.js 的版本(也可以使用 nvm list)。
nvm current

#使用 nvm use 需要以管理员的身份打开 PowerShell。
上次编辑于:
贡献者: qiaoweipeng