命令行窗口(小黑屏)、CMD窗口、终端、shell 的常用指令:
- dir: 列出当前目录下的所有文件
- cd 目录名: 进入到指定的目录
- md 目录名: 创建一个文件夹
- rd 目录名: 删除一个文件夹
Node.js
- 一门后端语言(服务器端的程序语言),能够连接数据库存取数据,能够接受和处理网络请求(服务器的响应,发送请求去获取数据),单线程事件驱动,异步执行,不等待,提高IO(Input/output)的处理速度和效率
- Node是一款对ES标准实现的JS引擎
- Node的中js引擎使用的chrome的v8引擎
- Node仅仅对ES标准进行了实现,所以在Node中不包含DOM 和 BOM
- Node的特点:
- 非阻塞、异步的I/O
- 事件和回调函数
- 单线程(主线程单线程,后台I/O线程池)
- 跨平台
包(package)
- 将多个模块组合为一个完整的功能,就是一个包
包结构
- bin: 二进制的可执行文件,一般都是一些工具包中才有
- lib: js文件
- doc: 文档
- test: 测试代码
- package.json: 包的描述文件,json格式
- name:包名
- version:版本
- dependencies:依赖
- main:包的主要的文件
- bin:可执行文件
npm(Node Package Manager node的包管理器)
- npm会在安装完node以后,自动安装
- 通过npm下载的包都放到node_modules文件夹中,可以直接通过包名引入即可
- npm的常用指令
1
2
3
4
5
6
7
8
9
10npm -v // 查看npm的版本
npm version // 查看所有模块的版本
npm init // 初始化项目(创建package.json)
npm i/install 包名 // 安装指定的包
npm i/install 包名 --save // 安装指定的包并添加依赖
npm i/install 包名 --save-dev // 安装的包只用于开发环境
npm i/install 包名 -g // 全局安装(一般都是一些工具)
npm i // 安装当前项目所依赖的包
npm s/search 包名 // 搜索包
npm r/remove 包名 // 删除一个包
node的全局对象 — global
- 在全局中创建的变量或函数都会作为global的属性或方法保存
模块化
- ES5中没有原生支持模块化,我们只能通过script标签引入js文件来实现模块化
- 在Node中为了对模块管理,引入了CommonJS规范
模块的定义
- 在Node中一个js文件就是一个模块
- 默认情况下在js文件中编写的内容,都是运行在一个独立的函数中,外部的模块无法访问
模块的引用: require()函数
- 可以传递一个文件的路径作为参数,Node将会自动根据该路径来引入外部模块
- 相对路径的引入:
1
require("./math");
- 绝对路径的引入:
1
require("fs");
- 相对路径的引入:
- 引入模块以后,该函数会返回一个对象,这个对象代表的是引入的模块
- 引入模块时,使用的就是模块标识,可以通过模块标识来找到指定的模块
暴露变量或方法: exports / module.exports
系统默认设置了 exports = modules.exports
- exports
- 只需要将需要暴露给外部的变量或方法设置为exports的属性即可
- 只能设置单个属性来向外暴露
- 向外部暴露属性:
1
exports.属性 = 属性值;
- 向外部暴露方法:
1
exports.方法名 = 函数;
- module.exports
- module.exports既可以单个设置属性也可以整个赋值,一切以module.exports为准
1
2
3module.exports.属性 = 属性值
module.exports.方法名 = 函数
module.exports = {}
- module.exports既可以单个设置属性也可以整个赋值,一切以module.exports为准
- 示例:
1
2
3
4
5
6
7
8
9
10
11存在
exports.a = 1
module.exports.b = 2
已知
exports = module.exports
因此
exports = {c:3}
不成立,输出时仍显示a,b
但
module.exports = {c:3}
成立, 输出为{c:3}
模块的初始化
- 一个模块中的js代码仅在模块第一次使用时执行一次
模块的类型
核心模块
- 由node引擎提供的模块
- 核心模块的标识就是,模块的名字
文件模块
- 由用户自己创建的模块
路径模块
1
let path = require("path")
- 获取路径信息扩展名: path.extname
1
let info = path.extname("https://www.baidu.com")
- 返回后缀名.com
- 将数组的元素自动拼接成一个路径: path.resolve()
1
2let arr = ['/sxt','xxx', 'ppp']
let info1 = path.resolve(...arr)- 返回:当前文件在的系统盘:\sxt\xxx\ppp
- 获取当前执行目录并拼接: path.join()
1
let info2 = path.join(__dirname, 'sxt', 'xxx', 'ppp')
- 解析网址: str.split(‘/‘)
- 解析路径(根路径、目录、扩展名、文件名称、文件名): path.parse(__filename)
1
2
3let url = require('url')
url.parse(httpUrl) --- 解析路径
url.resolve(targetUrl, httpUrl) --- 将两个路径合理拼接在一起
- 获取路径信息扩展名: path.extname
系统模块
1 | let os = require("os") |
- 查看cpu信息: os.cpus()
- 查看整个内存大小: os.totalmem()
- 查看系统架构: os.arch()
模块的标识(模块的名字或路径)
- 通过模块的标识来寻找模块的
- 对于核心模块(npm中下载的模块),直接使用模块的名字对其进行引入
- 对于自定义的文件模块,需要通过文件的路径来对模块进行引入
- 路径可以是绝对路径,如果是相对路径必须以./或 ../开头
模块的运行规则
- 当node在执行模块中的代码时,它会将代码放进以下函数中
1
function (exports, require, module, __filename, __dirname) {}
- 实际上模块中的代码都是包装在一个函数中执行的,并且在函数执行时,同时传递进了5个实参
- exports: 该对象用来将变量或函数暴露到外部
- require: 函数,用来引入外部的模块
- module: module代表的是当前模块本身
__filename
: 获取当前执行文件的完整路径__dirname
: 当前执行文件的目录的完整路径
模块的查找规则
- node在使用模块名字来引入模块时,它会首先在当前目录的node_modules中寻找是否含有该模块
- 如果有则直接使用,如果没有则去上一级目录的node_modules中寻找
- 如果有则直接使用,如果没有则再去上一级目录寻找,直到找到为止
- 直到找到磁盘的根目录,如果依然没有,则报错
- arguments.callee
- 这个属性保存的是当前执行的函数对象
事件
发送和接受事件
1 | let event = require("events") |
- 监听事件:
1
let ee.on('事件名', ()=> {})
- 触发事件:
1
let ee.emit('事件名',事件的数据data)
- 示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66let events = require("events")
let fs = require("fs")
let ee = new events.EventEmitter()
ee.on("test", (msg) => {
console.log(msg)
console.log("输出test")
})
// 同步
fsReadDir = () => {
fs.readdir("./", (err, files) => {
// files 是一个包含该目录所有文件的数组
if(!err) {
ee.emit("test",files)
} else {
console.log(err)
}
})
}
fsReadDir()
// 异步写法
const fsRead = (url: string) => {
return new Promise((resolve, reject) => {
fs.readFile(url, {flag: 'r', encoding: "utf-8"}, (err, data) => {
if(!err) {
resolve(data)
} else {
reject(err)
}
})
})
}
fsRead(path).then((res) => {
ee.emit("test",res)
})
|| 两者差不多,但下面少一个回调函数
const Test = async () => {
let res = await fsRead()
ee.emit("test",res)
}
Test()
// 老式写法
let Event = {
event: {},
on: (eventName, eventFn) => {
// 如果数组中存在这个事件,就及那个对应事件的函数赋给它,不存在则先添加事件名在赋值事件函数
if(this.event.eventName) {
this.event[eventName].push(eventFn)
} else {
this.event[eventName] = []
this.event[eventName].push(eventFn)
}
},
emit: (eventName, data) => {
// 数组存在这个事件就调用事件函数并返回数据
if(this.event[eventName]){
this.event[eventName].forEach(itemFn => {
itemFn(data)
})
}
}
}
eventEmitter.on("event1", (data) => {
// ... 一些事件
})