ES6+

ECMAScript是标准,JavaScript是其主要实现。

ES5的严格模式

1
'use strict'

严格模式下八进制的限制
严格模式下不允许使用0开头的八进制数字表示法(如012)。会抛出Uncaught SyntaxError: Octal literals are not allowed in strict mode。不过允许使用十六进制表示法(如0x12)。
设计原因: 数字前导零存在语义歧义(数学上012应与12等价),属于历史遗留问题。

严格模式下变量声明的限制
不允许未声明直接使用变量(如username = 100),会抛出username is not defined错误。
非严格模式对比: 普通模式下会自动创建全局变量,属于隐式变量声明。

let 与 const

◆ES6新增了let命令。

  • 不存在变量提升:let不像var那样会发生“变量提升”现象。所以,变量一定要在声明后使用,否则报错。
  • 暂时性死区:只要块级作用域内存在let命令,它所声明的变量就“绑定”这个区域,不再受外部的影响。
  • 不允许重复声明:let不允许在相同作用域内重复声明同一个变量。

    ES6规定暂时性死区和不存在变量提升,主要是为了减少运行时错误,防止在变量声明前就使用这个变量,从而导致意料之外的行为。 这样的错误在ES5中是很常见的,现在有了这种规定,避免此类错误就很容易了。

◆ES5只有全局作用域和函数作用域,ES6增加了块级作用域。
这其实带来了很多不合理的场景,内层变量可能会覆盖外层变量,用来计数的循环变量泄露为全局变量。

立即执行函数设计目的:隔离变量,避免污染全局作用域。 ES5 中 var 声明的变量无块级作用域,即使写在 {} 里,也会泄漏到外层(甚至全局)。IIFE 的解决方式就是用函数作用域包裹变量,强制隔离,避免泄漏。

所以,块级作用域的出现,实际上使得获得广泛应用的立即执行匿名函数(IIFE)不再必要了。

◆const与let不同的是,常量不可变,声明时必须立即赋值。

解构赋值

ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这就是解构(Destructuring)。

数组解构赋值

只要具有索引结构(通过下标访问元素),就可以解构。所以伪数组也可以。(字符串,arguments,DOM元素集合等)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**  错误 易混点
const data = ['one','two','three'];
lat list = [v1, v2, v3];
list = data;
**/

// 正确 左边是一个语法结构,不能存储变量! 右边是数组数据
const data = ['one','two','three'];
const [v1,v2,v3] = data;

// 解构赋值交换两个变量的值
[v1, v2] = [v2, v1]
// 以前:引入第三个临时变量t来交换

// 解构赋值用于函数传参 当实参数组元素多于形参时,只会按顺序匹配前几个元素!
function func([a, b ,c]){
console.log("a"+"b"+"c");
}
func(["小红","小明","小华"]);
func(data);

关于默认值
解构赋值允许指定默认值。.ES6内部使用严格相等运算符(===)判断一个位置是否有值。所以,如果一个数组成员不严格等于undefined,默认值是不会生效的。

1
2
3
4
5
6
var [f = true] = []; // f = true

var [a, b = 3] = [1, undefined]; //a = 1, b = 3

// null不严格等于undefined
var [x, y = 3] = [1, null] //x = 1, y = null

对象的解构赋值

对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

1
2
3
4
5
6
7
8
9
10
11
var {foo, bar} = {foo: "aaa", bar: "bbb"}; 
foo // "aaa"
bar // "bbb"

var{foo: baz} = {foo: "aaa"};
baz // "aaa"

let obj = {first: "hello", second: "world"};
let {first: f, second: l} = obj;
f // "hello"
l // "world"

所以,对象的解构赋值是以下形式的简写:

1
var {foo: foo, bar: bar} = {foo: "aaa", bar: "world"};

对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。

指定默认值

1
2
3
4
5
var {n1,n2:n2=22,n3=33,n4} = {n1:11};
n1 // 11
n2 // 22
n3 // 33
n4 // undefined

解构数组为对象

1
2
3
4
var {length, push, map} = [1, 2, 3, 4, 5];
length // 5
push // 函数
map // 函数

数组本质也是对象,具有 length 等内置属性。它可以解构出数组的内置方法和属性。

解构字符串为对象

1
2
3
4
var {length, indexOf, forEach} = "hello world";
length // 11
indexOf // 函数
forEach // undefined (函数没有forEach方法)

字符串新增特性

模板字符串
特点:

  1. 内部可以直接换行
  2. 内部可以直接插入变量或表达式 例如:${name}${age + 10}
    典型应用:用模板字符串动态生成HTML内容很方便

ES5 方法
charAt()
charCodeAt() 字符 -> 索引
indexOf() 返回子串首次出现的位置
lastIndexOf() 返回子串最后出现的位置
slice()
substring()
substr()
toLowerCase()
toUpperCalse()
split() 将字符串分割为数组
search() 正则搜索
match() 正则匹配
replace() 正则替换

ES6 + 方法
repeat(n) 字符串重复,返回新字符串
includes(‘a’) 判断是否包含a,返回布尔值
startsWith() 判断是否以某个值开始,返回布尔值
endsWith() 判断是否以某个值结尾,返回布尔值
trim() 去掉两端的空格
trimStart() 去掉前面的空格(ES2019)
trimEnd() 去掉后面的空格(ES2019)
padStart() 前面填充字符串(ES2017)
padEnd() 后面填充字符串(ES2017)
replaceAll() 替换字符串中指定内容,替换所有(ES2021)

1
2
3
4
5
'Hello World'.padStart(20) // 在前面补9个空格使总长度达20
'Hello World'.padStart(20, '@') // 在前面补9个@
'Hello World'.padEnd(30, '0') // 会在后面补19个0

' Hello World '.trimStart() // 去除前面所有空格

数值新增特性

二进制:使用0b前缀(如0b10表示二进制的2)
八进制:使用0o前缀(如0o10表示八进制的8)
十六进制仍然使用0x前缀。

输出特性:无论使用何种进制表示,控制台输出都会转换为十进制形式

Number 构造函数本身新增的方法和属性:
ES5

1
2
Number.MAX_VALUE;
Number.MIN_VALUE;

ES6+
Number.MAX_SAFE_INTEGER 读取最大的安全整数
Number.MIN_SAFE_INTEGER 读取最小的安全整数
Number.EPSILION 两个数字间最小差值,就是JS的数字精度

Number.isNaN() 同全局对象的 isNaN()
Number.isFinite() 同全局对象的 isFinite()
Number.parseInt() 同全局对象的 parseInt()
Number.parsetFloat() 同全局对象的 parsetFloat()
Number.isInteger() 判断参数是否是整数,返回布尔值
Number.isSafeInteger() 判断参数是否是安全整数,返回布尔值

Git

  1. github https://github.com/
  2. 码云 https://gitee.com/

开始

Git 是一款开源免费的分布式的版本控制系统。是 Linux 之父 Linus Torvalds(林纳斯·托瓦兹)为了方便管理 linux 代码代码而开发的。

功能:

  • 代码备份
  • 版本回退
  • 多人协作
  • 权限控制

Git 官方文档地址: https://git-scm.com/book/zh/v2

常用Linux命令
ls 将当前目录下所有的文件或子目录列举
ls -l 详细信息

rm -rf 删除(小心rm -rf /,全部格式化删除
clear 删除当前的执行记录

cd 进入到指定的目录

常用快捷键
ctrl + c 终止当前命令
ctrl + l 清除当前命令行
tab 自动补全路径
键盘上下方向键 调取历史命令

Vim的使用

1
2
3
4
5
6
7
8
9
vim <文件名.txt>

i # 进入输入模式,才能对文件进行编辑

esc # 回到命令模式

:w # 保存 vim :w! 强制保存
:q # 退出 vim
:wq # 保存并退出 vim

Git基础命令

初始化:每个新项目需要执行一次git init初始化,初始化会在项目目录下创建.git隐藏目录。

.git目录 :

  • hooks 目录包含客户端或服务端的钩子脚本,在特定操作下自动执行。
  • info 包含一个全局性排除文件,可以配置文件忽略。
  • logs 保存日志信息。
  • objects 目录存储所有数据内容,本地的版本库存放位置。
  • refs 目录存储指向数据的提交对象的指针(分支)。
  • config 文件包含项目特有的配置选项。
  • description 用来显示对仓库的描述信息。
  • HEAD 文件指示目前被检出的分支。
  • index 暂存区数据。

    不要手动去修改 .git 文件夹中的内容。

  1. 工作区:代码编辑区,开发者直接编辑文件的地方。所有修改首先在工作区进行。
  2. 暂存区:修改待提交区。通过git add命令将工作区修改添加到暂存区。
  3. 版本库:存储项目历史版本。通过git commit命令将暂存区内容提交到版本库。

    除了.git文件,其他都是工作区。

添加暂存区:

1
2
3
4
git add <file>    # 添加指定文件到暂存区
git add -u # 添加所有被删除或被修改的文件到暂存区(不包括新增文件)
git add . # 添加所有修改和新建的文件到暂存区(不包括删除的文件)
git add -A # 添加所有被删除、被替换、被修改和新增的文件到暂存区!

提交版本库:

1
2
git commit -m "提交日志"         # 把暂存区的东西提交到版本库
git commit -am "提交日志" # 把工作区的修改一步到位添加暂存并提交到版本库

查看状态和变化:

1
2
3
4
git status;
//对工作区和版本库进行比较。
//绿色 在暂存区
//红色 还在工作区

如果 git status 命令的输出对于你来说过于简略,而你想知道具体修改了什么地方,可以用 git diff 命令。

1
2
git diff             # 查看当前工作区和版本库的差异 (不包括新增的文件)
git diff --cached # 查看暂存区和版本库中的变化

撤销修改和撤销暂存

工作区的修改没有添加到暂存区

1
2
3
4
5
git restore <文件名>    # 恢复工作区指定文件
git restore . # 恢复工作区所有的修改(恢复之后,新增的文件不会被删除)

git checkout -- <file> # 同上 作用一致
git checkout -- . # 同上 作用一致

工作区的修改已经添加到暂存区
如果工作区的修改已经添加到暂存区,先清除暂存区,再恢复工作区。

1
2
git restore --staged <文件名>      # 把指定文件从暂存区移除
git restore --staged . # 把所有文件从暂存区移除

历史版本回滚

查看历史版本号:

1
2
3
git log		# 查看提交记录
git log -n # 查看最近的 n 次提交几次,n 是个数字
git log --oneline # 每次提交记录只用一行显示

通过指定版本号回滚:

1
git reset --hard <commitID>  # 版本号前七位即可

如果需要查看被回滚掉的提交的版本号:

1
git reflog

快捷回滚:

1
2
3
git reset --hard HEAD^    # 恢复到上个版本
git reset --hard HEAD^^ # 恢复到上上个版本
git reset --hard HEAD^^^ # 恢复到上上上个版本

Git忽略文件

哪些文件需要被 git 忽略:

  1. 忽略操作系统自动生成的文件,比如缩略图等;
  2. 忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如 Java 编译产生的.class文件;
  3. 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。

设置忽略文件 .gitignore
忽略文件的文件名是 .gitignore 的文件, 文件内可以设置项目的忽略规则。

忽略文件可以放在项目中的任意目录中,放在哪个目录作用范围就是哪个目录; 一般忽略文件会放在项目的根目录下。

Node与模块化

官方网站地址: https://nodejs.org/en/
中文网站地址 : http://nodejs.cn/

开始

Node.js,也称 Node,是一个基于 Chrome V8 引擎的 JavaScript 运行环境(宿主),与浏览器是等价的。

Node.js不是一种独立的语言,也不是一个JS框架或库,运行在Node.js上的JS不能使用DOM,BOM,但是可以使用Node.js提供的各种API。

有什么用?

  • 基于Node进行后端开发
  • 前端工程化支持(Wepack/Gulp等工具链)
  • 开发桌面应用(框架Electron、ReactNative等)
  • 开发小工具(自动化脚本、爬虫程序等)

特点:

  • 单线程
  • 非阻塞
  • 事件驱动

前端是指运行在客户端上的代码,特指WEB前端时即运行在浏览器上的代码,如HTML、CSS和JavaScript构建的页面。
后端是指运行在服务器端的程序,主要负责业务逻辑实现、数据库操作等功能,也称为服务端。

后端开发的组成

  • 后端编程语言(PHP、Java、C#、Go、Python、JavaScript)
  • Web服务器程序(Tomcat、Apache、Nginx、IIS等)
  • 数据库程序(MySQL、Oricle、MongoDB)

后端架构分层

  • 表现层:Node.js
  • 业务层:Java等
  • 底层:C/C++

cmd :不支持ls等Linux命令
PowerShell : 比cmd强大
GitBash : 支持完整Linux命令

REPL方式运行
(临时计算或快速测试)
进入REPL:命令行或终端运行 node ,就进入了 repl 模式
退出REPL:.exit 或者 按两下 ctrl+c 或者 ctrl+d
常用REPL命令:

  • ctrl + c - 按下两次 - 退出 Node REPL。
  • ctrl + d - 退出 Node REPL.
  • 向上/向下键 - 查看输入的历史命令
  • tab 键 - 列出当前变量(对象)

脚本运行

内置常量
dirname 获取JS脚本所在目录的绝对路径
__filename 获取JS脚本自己的绝对路径

1
2
console.log(dirname); 
console.log(__firname);

Buffer

Buffer 是 Node.js 提供的用于存储二进制数据的类数组对象(长得像数组,但本质是底层内存的直接映射),它的大小在创建时固定,无法动态调整,且存储的是 0~255 之间的整数值(对应字节)。

1 byte 字节 = 8 Bit (1Bit对应的是一个二进制位)
1024 byte = 1KB
一个 UTF-8 的中文字符大多数情况都是占 3 个字节。

创建Buffer

1
2
3
4
5
6
const b1 = Buffer.alloc(12); // 创建12字节Buffer并自动填充0
console.log(b1); // 输出:<Buffer 00 00 00 00 00>

const b2 = Buffer.from('Hello'); // 根据字符串 "Hello" 生成 Buffer
console.log(b2); // 输出:<Buffer 48 65 6c 6c 6f>(Hello 的 utf8 二进制编码)
console.log(b2.toString()); // 转回字符串:Hello

读取Buffer

1
2
3
4
5
6
7
8
9
10
const b = Buffer.from("hello 嘻嘻嘻");

console.log(b); // 16进制
console.log(b[0]); // 十进制

b.forEach((item, index) => {
console.log(item, index);
})

b.toString();

buffer 每个元素能表示的最大数字是 255,如果超过 255 的数字,会舍去高位(二进制)

1
2
buff3[0] = 365;                    // ‭0001 0110 1101‬ 
console.log(buff3[0]); // 109

为什么给 Buffer 的元素赋值 365,最终输出却是 109?
Buffer 的每个元素本质是 8 位无符号整数(0~255),只能存储 8 个二进制位,超过 255 的数字会被截断高位,只保留最后 8 位二进制数,再转为十进制。

内置模块

Noode 当中的模块分为三种:内置模块,第三方模块以及自定义模块。 不论哪一种模块,在使用时都必须先引入模块。

1
2
3
4
const 变量 = require('模块');
//比如path模块
const path = require('path');

关于抛错:

  1. try 里面的错误会被 catch 捕获,不论是代码错误还是主动抛出,捕获到错误之后由程序员处理,系统不会报错
  2. try catch 不论是否抛出错误,都不影响后面的语句的执行
  3. try 内部,错误后面的语句不会执行
1
2
3
4
5
6
7
8
9
try {
// 系统报错 调用不存在的函数
getInfo();

// 主动抛出的错误
// throw new Error('xiaole is not defiend');
} catch (err) {
console.log('捕获到错误:', err.errno, err.message);
}

Path模块

  • path.join([path1][, path2][, ...]) 用于连接路径。该方法的主要用途在于,会正确使用当前系统的路径分隔符,Unix系统是”/“,Windows系统是”\“。
  • path.isAbsolute(path) 判断参数path是否是绝对路径。
  • path.dirname(p) 返回路径中目录的部分 。
  • path.basename(p) 返回路径中的最后一部分,文件名部分。
  • path.extname(p) 返回路径中文件的后缀名。
  • path.resolve() 将路径或者路径片段序列化为绝对路径 (常用)。

fs模块(文件系统模块)

文件读取:

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
// 引入模块
const fs = require('fs');
const path = require('path');

// 要读取文件的路径
const filename = path.join(__dirname, './data/a.txt');


// ----------------------------------------------------
// 异步方式 读取文件内容
/*
fs.readFile(filename, (err, data) => {
if (err) {
console.log('文件读取失败:', err);
return; //不加return的话会继续执行后面代码然后报错
}
// console.log(data); // Buffer 数据
console.log(data.toString());
});
console.log('开始读取...');
*/

// 指定编码方式 直接对读取到二进制数据进行编码
fs.readFile(filename,'utf-8', (err, data) => {
if (err) {
console.log('文件读取失败:', err.errno, err.code);
return;
}
console.log(data);

});
console.log('开始读取...');


// ------------------------------------------------------
// 同步方式读取文件内容
// try {
// // const data = fs.readFileSync(filename);
// const data = fs.readFileSync(filename, 'utf-8');
// console.log(data);
// } catch (error) {
// console.log('文件读取失败:', error.errno, error.code);
// }
// console.log('开始读取...');

写入文件:

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
// 导入模块
const fs = require('fs');
const path = require('path');


// 要写入文件的地址
// const filename = path.join(__dirname, './data/b.txt');
const filename = path.resolve('./data/b.txt');

// 要写入的内容
const data01 = '你好小乐' + Math.random() + '\n';
// const data02 = Buffer.alloc(20, 100);

// -----------------------------------------------------
// 异步f方式 写入文件
fs.writeFile(filename, data01, err => {
if (err) {
console.log('写入失败!', err.errno, err.code);
} else {
console.log('写入成功!');
}
});
//从头开始写入 再次运行不会多加这个内容 而是覆盖


// ----------------------------------------------------------
// 同步方式 写入文件
try {
fs.writeFileSync(filename, data01);
console.log('写入成功!');
} catch (err) {
console.log('写入失败!');
};


// -------------------------------------------------------------------
// 同步方式写入 追加写
try {
for (let i = 0; i <= 10000; i ++) {
fs.appendFileSync(filename, data01);
}
} catch (err) {
console.log('写入失败!');
}

文件重命名:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 导入模块
const fs = require('fs');

// ---------------------------------------------------
// 重命名 将a.txt 改成 a.md
fs.rename('./data/a.txt', './data/a.md', err => {
if (err) {
console.log('重命名失败!');
} else {
console.log('重命名成功!');
}
});


// ---------------------------------------------------
// 其实也移动文件的位置
fs.rename('./data/a.md', './a.md', err => {
if (err) {
console.log('重命名失败!');
} else {
console.log('重命名成功!');
}
});

删除文件:

1
2
3
4
5
6
7
8
9
10
11
const fs = require('fs');

fs.unlink('./a.md', err => {
if (err) {
console.log('文件删除失败!');
} else {
console.log('文件删除成功!');
}
})

// fs.unlinkSync()同步

创建目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 异步方式 创建目录 递归方式创建多级目录 
fs.mkdir(newDir, {recursive:true},err => {
if (err) {
console.log('创建目录失败:', err.message);
} else {
console.log('创建目录成功!');
}
});

// 同步方式 创建目录
try {
fs.mkdirSync(newDir);
// fs.mkdirSync(newDir,{recursive:true}); 递归方式创建多级目录
} catch (err) {
console.log('目录创建失败:', err.message);
}

URL模块

querystring 模块

JSON 格式的处理

JSON全称是 JavaScript Object Notation (JavaScript 对象表示法) ,是一种轻量级的数据交换格式。

JSON 的语法与 JS 定义数组和对象的语法区别:

  1. json 中的字符串必须使用双引号
  2. json 中的属性名必须使用双引号包裹
  3. json 中的最后一个属性不能有逗号
  4. json 中的属性值不能是表达式
1
2
3
4
5
//将json格式的字符串转为对象
const obj = JSON.parse(json_data);

// 对象、数组 -> JSON
const json = JSON.stringify(strs);

Node 中的模块化

四种模块化规范:CommonJS规范、AMD规范、CMD规范、ES Module规范。

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

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

CommonJS 模块规范

引入模块(自定义模块)

1)使用require()引入模块,内置模块直接写模块名,自定义模块需要些相对路径。
2)自定义模块的地址必须以 ./../ 开头。因为模块文件的地址没有以 ./../ 开头时,会被认为是内置模块或第三方模块的模块名。
3)扩展名可以省略。如.js或.json。无扩展名时会依次查找同名js文件、json文件和目录。

1.扩展名是 .js的模块文件: 读取文件内容并编译执行并获取模块中暴露的数据。
2.扩展名是.json的模块文件: 读取文件时会自动用 JSON.parse() 解析返回结果作为获取的数据。

整个目录作为一个模块
1)会默认加载该目录下 package.json 文件中 main 属性定义的入口文件。
2)如果没有package.json, 或者 main 属性对应的文件不存在,则自动找 index.jsindex.json 作为入口文件。

模块暴露数据

模块中定义了变量但未暴露,外部无法访问。require返回空对象{},无法访问模块内部变量。
模块中通过module.exports赋值暴露数据,绝大多数暴露的是对象类型,因为信息承载量更大。
本质原理:module.exports实际上是模块对外暴露的接口对象,require()的返回值就是这个对象。

1
module.exports = obj;

当模块暴露的是对象时,可以使用解构赋值直接获取属性。要注意解构出的方法如果直接调用,this会指向全局对象而非原模块对象。

通过给module.exports添加getMessagesetMessage两个方法,可以实现暴露多个数据。

1
2
3
4
5
6
module.exports.getMessage = () => {
//内容
}
module.exports.getMessage = () => {
//内容
}

对象引用与exports赋值的原理 :对象存储在堆中,变量名(如exports)存储在栈中,指向堆中的对象。module.exports默认指向一个空对象,exports是它的别名,也指向这个空对象。给exports添加属性实际上是给这个空对象添加属性。如果修改exports的值(重新赋值),则exports会指向新的对象,与module.exports的引用关系断开,导致无法暴露数据。

ES6 模块规范

引入模块

1
2
3
4
5
6
7
// 类似解构导入 
import {writeFile, readFile} from "node:fs";
writeFile('data.txt', 'hello',err=>{});

// 导入fs模块的所有导出成员,并挂载到fs这个命名空间对象上
import * as fs from 'node:fs';
fs.writeFile('data.txt', 'hello',err=>{});

Node.js 要求 ES6 模块采用.mjs后缀文件名。也就是说,只要脚本文件里面使用import关键字,那么就必须采用.mjs后缀名。
如果不希望将后缀名改成.mjs,可以在项目的package.json文件中,指定type字段为module。 此时,只能使用ES6模块语法(import/export)。

模块暴露数据

使用 export default 可以在模块中暴露单个数据,注意文件中 export default 语句只能出现一次。

使用 export 可以暴露多个数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 第一种写法 在声明变量的同时暴露
export const year = 1918;
export function fn() {};
export const obj = {name:'mingge',age:100};


// 第二种写法 在文件底部统一暴露(推荐)
const firstName = 'Lee';
const lastName = 'KeQiang';
const year = 1918;
function fn() {};
const obj = {name:'mingge',age:100}

export {firstName, lastName, year, fn, obj};

引入模块并使用模块中暴露的数据:

1
2
3
4
5
6
7
// import 变量名 from '模块地址';
// 获取的变量名必须与模块暴露的变量名一致,可以多次分别获取,可以取别名
import {name, year as y} from '模块地址';
import {fn} from '模块地址';

// 可以将模块中的数据整体加载
import * as 别名 from '模块地址';

NPM

NPM官网:npm | Home
npm类似于手机应用商店或电脑软件管家,是一个集中管理各种开发包的工具平台。官网上托管了大量开发者共享的包,包括流行框架如Vue、React等。此时需要通过命令行工具进行下载,而非直接从网站下载。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
npm -v
npm init -y # 快速初始化
npm install # 等价于npm i

npm install 包名 -g # 全局安装 主要安装命令行工具

# 安装指定的版本
npm install 包名@版本号
npm install 包名@版本号 -g

# 删除包
npm remove 包名
npm remove 包名 -g

# 更新包
npm update 包名
npm update 包名 -g

# 安装依赖
npm install # 根据package.json 安装所需依赖

# 清除缓存
npm cache clean --force # force 表示强制清除

package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"name": "01-project", // 包名
"version": "1.0.0", // 版本
"description": "", // 描述信息
"main": "index.js", // 入口文件
"scripts": { // 可执行的名
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "", // 作者信息
"license": "ISC", // 开源许可
"dependencies": { // 依赖信息
"bootstrap": "^5.1.3",
"jquery": "^3.6.0"
}
"devDependencies": { // 开发中的依赖
"babel": "^6.23.0"
}
}

当删除node_modules后运行程序会报错,因为缺少依赖模块。package.json中记录了项目所需的所有依赖包及其版本。通过npm install命令可以自动安装所有依赖。

版本锁定规则
^3.0.0:锁定大版本(3.x.x)
~3.1.0:锁定小版本(3.1.x)
3.1.1:锁定完整版本
package-lock.json:精确锁定安装时的具体版本。

依赖包列表
依赖类型:

  • dependencies:生产依赖(开发和运行都需要,项目本身需要)
  • devDependencies:开发依赖(仅开发过程需要,项目本身不需要)
    安装方式:
  • npm install 包名 --save:安装为生产依赖
  • npm install 包名 --save-dev:安装为开发依赖

模块的查找过程

  1. 先确定模块名路径是不是以 ./ 或者 ../ 开头,如果不是就认为是内置模块或者第三方模块
  2. 再确定有没有该内置模块,如果有该内置模块直接加载;如果没有该内置模块,判定为第三方模块。
  3. 第三方模块加载过程:
    ① 先从脚本本就所在的目录中查找有没有 node_modules 目录,如果有进入查找模块。
    ② 如果脚本同级目录没有 node_modules 目录,去上级目录查找 node_modules 目录,如果有进入查找模块。
    ③ 以此类推,一直查找到 根目录。

远程仓库与npm

克隆的项目不包含node_modules目录,必须执行npm install才能正常运行项目,依赖安装应在项目根目录下执行。

配置命令别名

配置 package.json 中的 scripts 属性:

1
2
3
4
5
6
{
"scripts": {
"server": "node server.js",
"start": "node index.js",
},
}

配置完成之后,可以使用别名执行命令:

1
2
npm run server
npm run start

不过 start 别名比较特别,使用时可以省略 run:

1
npm start

所以,对于陌生的项目,可以通过查看 scripts 属性来参考项目的一些操作。

cnpm

使用npm下载包时,会去npm官网下载,而npm服务器在国外,可能不稳定。

cnpm使用国内镜像作为npm源,解决官方源在国外导致的下载不稳定问题。淘宝镜像(npmmirror.com)每10分钟同步一次npm官方仓库,提供国内高速下载。

总结特点:

  • 与npm命令完全兼容,仅需替换命令前缀。
  • 支持所有npm操作(安装、初始化、发布等)。
  • 镜像服务器位于阿里云,网络稳定性更高。

全局安装 cnpm 命令,安装完成后使用 cnpm 命令代替 npm 命令。

1
npm install -g cnpm --registry=https://registry.npmmirror.com

yarn

Yarn 由 Meta 推出,核心优势是缓存、并行下载、精确版本锁定。

全局安装yarn:

1
npm install -g yarn

基础命令:

1
2
3
4
5
6
yarn --version #查看版本
yarn init #初始化项目
yarn add 包名 #安装依赖(相当于npm install)
yarn add 包名 --dev #开发依赖(相当于--save-dev)
yarn global add 包名 #全局安装
yarn remove 包名 #移除依赖

发布npm包

HTTP协议

IP地址
IP地址是IP协议提供的统一地址格式,为互联网上每个网络和主机分配的唯一标识。每个联网设备(电脑、手机、智能家居等)都必须有唯一IP地址。采用分层结构解决地址不足问题(局域网使用私有IP,对外共用公网IP)。当前主流IPv4格式为点分十进制,地址组合数为256^4种。IPv6是为解决地址不足问题推出的新格式。

域名

Express

Ajax

Promise

Axios