从最基础的Node.js入手

一、JavaScript模块化

事实上模块化最终的目的就是将程序划分为一个个小小的结构,这个接口可以将自己希望暴露的变量、函数、对象等,这里提到的结构,就是模块,按照这种结构划分开发程序的过程,就是模块化开发的过程。

1. CommonJS规范

1.2 CommonJs和Node

CommonJs是一个规范,Node是CommonJS在服务端的一个具有代表性的实现。在Node中每一个js文件都是一个单独的模块。这个模块包括CommonJS规范的变量:exports、module.exports、require

1.3 exports导出

exports是一个对象,是对象,就会在内存中开辟一个存储空间,将这个对象存到对应的空间里,我们也就可以在对象中添加很多个属性。另一个文件中可以用require导入,require的本质是一个函数,可以帮助我们引入一个文件(模块)中导入的对象(下面会说)

1.4 module.exports又是什么

CommonJS中是没有module.exports的概念的,但是为了实现模块的导出,Node中使用的是Module的类,每一个模块都是Module的一个实例,也就是 module。所以在Node中真正用于导出的其实根本不是exports,而是module.exports,因为module才是导出的真正实现者。

1.5 require细节

我们从上面知道,require本质是一个函数,可以帮助我们引入一个文件(模块)中导入的对象。
导入格式:require(*)

其中 * 可以是一个核心模块,比如path、http等
*也可以是意 ./或者…/或者(跟目录)开头的
**注意:**如果是一个没有路径的 * 引入,并且也不是一个核心模块,那就会报 not found 的错误。

1.6 模块化加载过程

模块在被第一次引入时,模块中的js代码会被运行一次,模块被多次引入时,会缓存,最终只运行加载一次,如果是循环引入,那么加载的顺序就是一个图结构中的深度优先搜索遍历(如图)
最终顺序是:mian–>a–>c–>d–>e–>b
从最基础的Node.js入手_第1张图片

2. ES Module

ES Module 使用了import和export关键字,采用编译器的静态分析,也加入了动态引用的方式。其中,exports负责将模块内的内容导出,import负责从其他模块导入内容。

注意: 采用ES Module将自动采用严格模式:**use strict **

2.1 exports 关键字

export关键字将一个模块中的变量、函数、类等导出。它有如下三种导出方式
方式一: 在语句声明的前面直接加上export关键字
方式二:将所有需要导出的标识符,放到export后面的 {}

注意:这里{}不是一个对象!!!是一个语法

方式三: 导出时给标识符起一个别名

2.2 import 关键字

import关键字负责从另外一个模块中导入内容。它有如下三种导入方式
方式一:import {标识符列表} from ‘模块’;

注意:这里的{}也不是一个对象,里面只是存放导入的标识符列表内容。

方式二:导入时给标识符起别名。
方式三:通过 * 将模块功能放到一个模块功能对象(a module object)上

2.3 default 用法

在ES Module 中还有一种导出叫默认导出,默认导出是不需要指定名字的,在导入时不需要使用{},并且可以自己来指定名字

注意:在一个模块中,只能有一个默认导出(default export)

2.4 import 函数

我们通过import 来加载模块时,是不可以将其放到逻辑代码中的,如果我们确确实实希望动态的来加载一个模块,这个时候就需要用到 import() 函数来动态加载。

注意:加了()的import就是一个函数了

3. CommonJS 与 ES Module

CommonJS ES Module
加载过程 运行时加载,是同步的 解析时加载,是异步的
**CommonJS **运行时加载意味着是js引擎在执行js代码的过程中加载模块,同步的就意味着一个文件没有加载结束之前,后面的代码都不会执行。

ES Module加载js文件的过程是编译(解析)时加载的,并且是异步的,编译时(解析)时加载,意味着import不能和运行时相关的内容放在一起使用。①比如from后面的路径需要动态获取,②比如不能将import放到if等语句的代码块中。所以我们有时候也称ES Module是静态解析的,而不是动态或者运行时解析的。(异步意味着 JS引擎在遇到import时会去获取这个js文件,但是这个获取的过程是异步的,并不会阻塞主线程继 续执行 )
**ES Module **加载加载过程中,通过export导出的是变量本身的引用。export在导出一个变量时,js引擎会解析这个语法,并且创建模块环境记录(module environment record),模块环境记录会和变量进行 绑定(binding),并且这个绑定是实时的,而在导入的地方,我们是可以实时的获取到绑定的最新值的。

二、Node常用的内置模块

1. 内置模块 path

path模块用于对路径和文件进行处理,提供了很多好用的方法。可用于处理不同系统上路径不同的问题。

注意:尽量不要使用手动拼接路径,要让 node 帮我们执行

1.1 path 常见的API

① 从路径中获取信息:

  • dirname:获取文件的父文件夹;
  • basename:获取文件名;
  • extname:获取文件扩展名

② 路径拼接:

  • 利用 path.join(简单的直接拼接)

③ 将文件和某个文件拼接

  • 利用path.resolve(用的最多

注意: resolve函数会判断我们拼接的路径前面是否有 /或…/或./ 开头的路径
有:表示一个绝对路径,会返回对应的拼接路径
没有:会和当前执行文件所在的文件夹路径进行拼接

1.2 内置模块 fs( File System )

借助于Node帮我们封装的文件系统,我们可以在任何的操作系统(window、Mac OS、Linux)上面直接去 操作文件。

① 文件系统的API大多数都是提供三种操作方式:

  • 同步操作文件:代码会被阻塞,不会继续执行。
  • 异步回调函数操作文件:代码不会被阻塞,需要传入回调函数,当获取到结果时,回调函数被执行。
  • 异步Promise操作文件:代码不会被阻塞,通过 fs.promises 调用方法操作,会返回一个Promise, 可以通过then、catch进行处理

② 文件的读写(对文件内容进行操作)

  • fs.readFile(path[,** options**], callback):读取文件的内容
  • fs.writeFile(file, data[, options], callback):在文件中写入内容

其中,option中可填入flag(写入的方式)选项和 encoding(字符编码)

③ 文件夹操作

  • 使用fs.mkdir()或fs.mkdirSync()创建一个新文件夹
  • 获取文件夹内容
  • 文件重命名

1.3 events模块

注意: Node中的核心API都是基于异步事件驱动,在这个体系中,某些对象( 发射器(Emitters))发射出某一个事件,我么可以监听(listenners)到这个时间,并且传入回调函数,这个回调函数会在监听到事件时来调用。

**① EventEmitter类 **

  • emitter.on(eventName, listener):监听事件,也可以使用 addListener
  • emitter.off(eventName, listener):移除事件监听,也可以使 用removeListener
  • emitter.emit(eventName[, …args]):发出事件,可以携带一 些参数
  • emitter.once(eventName, listener):事件监听一次
  • emitter.prependListener():将监听事件添加到最前面
  • emitter.prependOnceListener():将监听事件添加到最前面,但是只监听一次
  • emitter.removeAllListeners([eventName]):移除所有的监听器

** ② EventEmitter的实例的一些属性 **

  • emitter.eventNames():返回当前 EventEmitter对象注册的事件字符串数组
  • emitter.getMaxListeners():返回当前 EventEmitter对象的最大监听器数量,可以通过setMaxListeners() 来修改,默认是10
  • emitter.listenerCount(事件名称):返回当前 EventEmitter对象某一个事件名称,监听器的个数
  • emitter.listeners(事件名称):返回当前 EventEmitter对象某个事件监听器上所有的监听器数组

三、包管理工具

1. 包管理工具npm

Node Package Manager,也就是Node包管理器。
官网:npm包的官网
包的存放:我们发布自己的包其实是发布到registry上面的,当我们安装一个包时也是从registry上面下载的包

1.1项目配置文件

在node环境下面(无论前端还是后端)配置文件都是 package.json

① 常见属性:

  • name(必写):项目的名称
  • version:当前项目的版本号
  • description:描述信息
  • author:作者相关信息
  • license:开源项目协议
  • main:设置程序的入口
  • scripts: scripts属性用于配置一些脚本命令,以键值对的形式存在
  • dependencies:dependencies属性是指定无论开发环境还是生成环境都需要依赖的包,通常是我们项目实际开发用到的一些库模块 。
  • devDependencies:一些包在生成环境是不需要的,比如webpack、babel等

注意: 那么在生成环境如何保证不安装这些包呢?
答:生成环境不需要安装时,我们需要通过 npm install --production 来安装文件的依赖

1.2 版本管理问题

npm的包通常需要遵循semver版本规范

① semver版本规范是X.Y.Z:

  • X主版本号(major):当你做了不兼容的 API 修改(可能不兼容之前的版本);
  • Y次版本号(minor):当你做了向下兼容的功能性新增(新功能增加,但是兼容之前的版本);
  • Z修订号(patch):当你做了向下兼容的问题修正(没有新功能,修复了之前版本的bug);
  • ^x.y.z:表示x是保持不变的,y和z永远安装最新的版本;
  • ~x.y.z:表示x和y保持不变的,z永远安装最新的版本 。

② 常见属性:

  • engines :用于指定Node和NPM的版本号
  • browserslist : 用于配置打包后的JavaScript浏览器的兼容情况

1.3 npm install 命令

  • 全局安装:npm install yarn -g
  • 局部安装:npm install

1.4 项目安装

项目安装会在当前目录下生产一个 node_modules 文件夹

① 安装开发和生产依赖

  • npm install axios
  • npm i axios

② 开发依赖

  • npm install webpack --save-dev
  • npm install webpack -D
  • npm i webpack –D

③ 根据package.json中的依赖包

  • npm install

1.5 npm 其他命令

① 卸载某个依赖包

  • npm uninstall package
  • npm uninstall package --save-dev
  • npm uninstall package -D

② 强制重新build

  • npm rebuild

**③ 清除缓存 **

  • npm cache clean

1.6 npm install 原理

从最基础的Node.js入手_第2张图片

2. yarn 工具

yarn 是为了弥补 npm 的一些缺陷而出现的

你可能感兴趣的