From ad6cdc1050f8f78a2d71c4b0eb93ab10dbefd80f Mon Sep 17 00:00:00 2001 From: jaywcjlove Date: Tue, 27 Sep 2022 16:56:28 +0000 Subject: [PATCH] chore: add github workflows config. 49788a09b3bb69d1f27de8c14edf900796415a13 --- .nojekyll | 0 docs/cron.html | 241 ++++++++ docs/git.html | 311 +++++++++++ docs/javascript.html | 1260 ++++++++++++++++++++++++++++++++++++++++++ docs/jest.html | 520 +++++++++++++++++ docs/json.html | 439 +++++++++++++++ docs/markdown.html | 205 +++++++ docs/toml.html | 185 +++++++ docs/typescript.html | 904 ++++++++++++++++++++++++++++++ docs/vscode.html | 611 ++++++++++++++++++++ index.html | 37 ++ style/style.css | 612 ++++++++++++++++++++ 12 files changed, 5325 insertions(+) create mode 100644 .nojekyll create mode 100644 docs/cron.html create mode 100644 docs/git.html create mode 100644 docs/javascript.html create mode 100644 docs/jest.html create mode 100644 docs/json.html create mode 100644 docs/markdown.html create mode 100644 docs/toml.html create mode 100644 docs/typescript.html create mode 100644 docs/vscode.html create mode 100644 index.html create mode 100644 style/style.css diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/docs/cron.html b/docs/cron.html new file mode 100644 index 00000000..fe882c71 --- /dev/null +++ b/docs/cron.html @@ -0,0 +1,241 @@ + + + + +Cron 备忘清单 + & Quick Reference + + + + + +

Cron 备忘清单

+

Cron 最适合安排重复性任务。 可以使用关联的 at 实用程序来完成一次性任务的调度。

+

Crontab 格式

+

格式

+
Min  Hour Day  Mon  Weekday
+分钟  小时  天   月  周
+
+
+
*    *    *    *    *  要执行的命令
+┬    ┬    ┬    ┬    ┬
+│    │    │    │    └─  星期几         (0=周日 .. 6=星期六)
+│    │    │    └──────  月            (1..12)
+│    │    └───────────  月份中的某天    (1..31)
+│    └────────────────  小时           (0..23)
+└─────────────────────  分钟           (0..59)
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
字段范围特殊字符
分钟 Minute0 - 59, - * /
小时 Hour0 - 23, - * /
月份中的某天1 - 31, - * ? / L W
月 Month1 - 12, - * /
星期几0 - 6, - * ? / L #
+

示例

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ExampleDescription
*/15 * * * *每 15 分钟
0 * * * *每隔一小时
0 */2 * * *每 2 小时
15 2 * * *每天凌晨 2 点 15 分
15 2 * * ?每天凌晨 2 点 15 分
10 9 * * 5每周五上午 9:10
0 0 * * 0每个星期日的午夜
15 2 * * 1L每月最后一个星期一凌晨 2 点 15 分
15 0 * * 4#2每个月的第二个星期四早上 00:15
0 0 0 1 * *每个月的 1 日(每月)
0 0 0 1 1 *每年 1 月 1 日(每年)
@reboot每次重启 (非标准)
+

特殊字符串

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
特殊字符串意义
@reboot运行一次,在系统启动时 (非标准)
@yearly每年运行一次,“0 0 1 1 *” (非标准)
@annually(与@yearly 相同)(非标准)
@monthly每月运行一次,“0 0 1 * *” (非标准)
@weekly每周运行一次,“0 0 * * 0” (非标准)
@daily每天运行一次,“0 0 * * *” (非标准)
@midnight(与@daily 相同)(非标准)
@hourly每小时运行一次,“0 * * * *” (非标准)
+

Crontab 命令

+ + + + + + + + + + + + + + + + + + + + + + + + + +
--
crontab -e如果不存在,则编辑或创建一个 crontab 文件。
crontab -l显示 crontab 文件。
crontab -r删除 crontab 文件。
crontab -v显示您上次编辑 crontab 文件的时间。 (非标准)
+

特殊字符

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
特殊字符说明
Asterik(*)匹配字段中的所有值或任何可能的值。
Hyphen(-)用于定义范围。例如:第 5 个字段(星期几)中的 1-5 每个工作日,即星期一到星期五
Slash (/)第一个字段(分钟)/15 表示每十五分钟或范围的增量。
Comma (,)用于分隔项目。例如:第二个字段(小时)中的 2、6、8 在凌晨 2 点、早上 6 点和早上 8 点执行
L仅允许用于 月份中的某天星期几 字段,星期几 中的 2L 表示每个月的最后一个星期二
Hash (#)仅允许用于 星期几 字段,后面必须在 1 到 5 的范围内。例如,4#1 表示给定月份的“第一个星期四”。
Question mark (?)可以代替“*”并允许用于月份和星期几。使用仅限于 cron 表达式中的 月份中的某天星期几
+

Also see

+ + +
+ diff --git a/docs/git.html b/docs/git.html new file mode 100644 index 00000000..c4f6cf21 --- /dev/null +++ b/docs/git.html @@ -0,0 +1,311 @@ + + + + +Git 备忘清单 + & Quick Reference + + + + + +

Git 备忘清单

+

本备忘单总结了常用的 Git 命令行指令,以供快速参考。

+

入门

+

创建存储库

+

创建一个新的本地存储库

+
$ git init [project name]
+
+

克隆存储库

+
$ git clone git_url
+
+

将存储库克隆到指定目录

+
$ git clone git_url 指定目录
+
+

做出改变

+

在工作目录中显示修改后的文件,为您的下一次提交暂存

+
$ git status
+
+

暂存文件,准备提交

+
$ git add [file]
+
+

暂存所有更改的文件,准备提交

+
$ git add .
+
+

将所有暂存文件提交到版本化历史记录

+
$ git commit -m "commit message"
+
+

将所有跟踪的文件提交到版本化历史记录

+
$ git commit -am "commit message"
+
+

取消暂存文件,保留文件更改

+
$ git reset [file]
+
+

将所有内容恢复到最后一次提交

+
$ git reset --hard
+
+

已更改但未暂存内容的差异

+
$ git diff
+
+

已 commited 但尚未提交的内容的差异

+
$ git diff --staged
+
+

在指定分支之前应用当前分支的任何提交

+
$ git rebase [branch]
+
+

配置

+

设置将附加到您的提交和标签的名称

+
$ git config --global user.name "name"
+
+

设置将附加到您的提交和标签 tags 的电子邮件地址

+
$ git config --global user.email "email"
+
+

启用 Git 输出的一些着色

+
$ git config --global color.ui auto
+
+

在文本编辑器中编辑全局配置文件

+
$ git config --global --edit
+
+

使用分支

+

列出所有本地分支

+
$ git branch
+
+

列出所有分支,本地和远程

+
$ git branch -av
+
+

切换到 my_branch,并更新工作目录

+
$ git checkout my_branch
+
+

创建一个名为 new_branch 的新分支

+
$ git checkout -b new_branch
+
+

删除名为 my_branch 的分支

+
$ git branch -d my_branch
+
+

将分支 A 合并到分支 B

+
$ git checkout branchB
+$ git merge branchA
+
+

标记当前提交

+
$ git tag my_tag
+
+

观察你的存储库

+

显示当前活动分支的提交历史

+
$ git log
+
+

显示 branchA 上不在 branchB 上的提交

+
$ git log branchB..branchA
+
+

显示更改文件的提交,即使跨重命名

+
$ git log --follow [file]
+
+

显示 branchA 中的内容与 branchB 中的内容的差异

+
$ git diff branchB...branchA
+
+

以人类可读的格式显示 Git 中的任何对象

+
$ git show [SHA]
+
+

同步

+

从该 Git 远程获取所有分支

+
$ git fetch [alias]
+
+

将远程分支合并到当前分支以使其保持最新状态

+
$ git merge [alias]/[branch]
+# 没有快进
+$ git merge --no-ff [alias]/[branch]
+# 仅快进
+$ git merge --ff-only [alias]/[branch]
+
+

将本地分支提交传输到远程存储库分支

+
$ git push [alias] [branch]
+
+

从跟踪远程分支获取并合并任何提交

+
$ git pull
+
+

将另一个分支的一个特定提交合并到当前分支

+
$ git cherry-pick [commit_id]
+
+

远程

+

添加一个 git URL 作为别名

+
$ git remote add [alias] [url]
+
+

显示您设置的远程存储库的名称

+
$ git remote
+
+

显示远程存储库的名称和 URL

+
$ git remote -v
+
+

删除远程存储库

+
$ git remote rm [remote repo name]
+
+

更改 git repo 的 URL

+
$ git remote set-url origin [git_url]
+
+

临时提交

+

保存已修改和分阶段的更改

+
$ git stash
+
+

列出隐藏文件更改的堆栈顺序

+
$ git stash list
+
+

从存储堆栈顶部编写工作

+
$ git stash pop
+
+

丢弃存储堆栈顶部的更改

+
$ git stash drop
+
+

跟踪路径更改

+

从项目中删除文件并暂存删除以进行提交

+
$ git rm [file]
+
+

更改现有文件路径并暂存移动

+
$ git mv [existing-path] [new-path]
+
+

显示所有提交日志,并指示任何移动的路径

+
$ git log --stat -M
+
+

忽略文件

+
/logs/*
+# “!” 意思是不要忽视
+!logs/.gitkeep
+# 忽略 Mac 系统文件
+.DS_store
+# 忽略 node_modules 文件夹
+node_modules
+# 忽略 SASS 配置文件
+.sass-cache
+
+

.gitignore 文件指定了 Git 应该忽略的未跟踪的文件

+

Git 技巧

+

重命名分支

+

重命名new

+
$ git branch -m <new>
+$ git branch -m <old> <new> # 重命名分支  
+
+

推送并重置

+
$ git push origin -u <new>
+
+

删除远程分支

+
$ git push origin --delete <old> # 方法1
+$ git push origin :oldBranchName # 方法2
+
+

Log

+

按内容搜索更改

+
$ git log -S'<a term in the source>'
+
+

显示特定文件随时间的变化

+
$ git log -p <file_name>
+
+

打印出很酷的日志可视化

+
$ git log --pretty=oneline --graph --decorate --all
+
+

分支

+

列出所有分支及其上游

+
$ git branch -vv 
+
+

快速切换到上一个分支

+
$ git checkout -
+
+

只获取远程分支

+
$ git branch -r
+
+

从另一个分支签出单个文件

+
$ git checkout <branch> -- <file>
+
+

删除本地存在远程不存在的分支

+
git remote prune origin
+
+

Commit

+
$ git commit -v --amend
+
+

重写最后的提交信息

+

忽略文件的权限变化

+
git config core.fileMode false
+
+

不再将文件的权限变化视作改动

+

Git 别名

+
$ git config --global alias.co checkout
+$ git config --global alias.br branch
+$ git config --global alias.ci commit
+$ git config --global alias.st status
+
+

也可以看看:More Aliases

+

设置大小写敏感

+
# 查看git 的设置
+$ git config --get core.ignorecase
+# 设置大小写敏感
+$ git config core.ignorecase false
+# 远程有俩相同目录,通过这种方式清除掉,然后提交记录
+$ git rm -r --cached <目录/文件> 
+
+

修改远程 Commit 记录

+
$ git rebase -i HEAD~3
+# 表示要修改当前版本的倒数第三次状态
+# 将要更改的记录行首单词 pick 改为 edit
+pick 96dc3f9 提交 commit 描述内容 1
+pick f1cce8a 提交 commit 描述内容 2
+pick 6293516 提交 commit 描述内容 3
+# Rebase eeb03a4..6293516 onto eeb03a4 
+#                     (3 commands)
+#
+# Commands:
+# p, pick = 使用提交
+# r, reword = 使用提交,但编辑提交消息
+# e, edit = 使用提交,但停止修改
+# s, squash = 使用提交,但融合到先前的提交中
+# f, fixup = 像 squash,但丢弃此提交的日志消息
+# x, exec = 使用 shell 运行命令(该行的其余部分)
+# d, drop = 删除提交
+
+

保存并退出,会弹出下面提示

+
# 您现在可以修改提交,使用
+# 
+#   git commit --amend
+# 
+# 对更改感到满意后,运行
+# 
+#   git rebase --continue
+#
+# 1. 通过这条命令进入编辑更改 commit,保存退出
+$ git commit --amend
+# 2. 保存退出确认修改,继续执行下面命令, 
+$ git rebase --continue
+# 如果修改多条记录反复执行上面两条命令直到完成所有修改
+
+# 最后,确保没有人提交进行推送,最好不要加 -f 强制推送
+$ git push -f origin master
+
+

撤销远程记录

+
# 撤销一条记录   
+$ git reset --hard HEAD~1
+# 强制同步到远程仓库  
+$ git push -f origin HEAD:master
+
+

放弃本地修改内容

+
# 如果有的修改以及加入暂存区的话
+$ git reset --hard 
+# 还原所有修改,不会删除新增的文件
+$ git checkout . 
+# 下面命令会删除新增的文件
+$ git clean -xdf
+
+

获取最近一次提交的 Hash

+
$ git rev-parse HEAD # e10721cb8859b2c
+# 获取短 hash
+$ git rev-parse --short HEAD # e10721c
+
+

删除已经合并到 master 的分支

+
$ git branch --merged master | grep -v '^\*\|  master' | xargs -n 1 git branch -d
+
+

中文乱码的解决方案

+
$ git config --global core.quotepath false
+
+

把 A 分支的某一个 commit,放到 B 分支上

+
# 切换到 B 分支
+$ git checkout <B>
+# 将 A 分支 <hash-id> 的内容 pick 到 B 分支
+$ git cherry-pick <hash-id>
+
+ +
+ diff --git a/docs/javascript.html b/docs/javascript.html new file mode 100644 index 00000000..26ea07ab --- /dev/null +++ b/docs/javascript.html @@ -0,0 +1,1260 @@ + + + + +JavaScript 备忘清单 + & Quick Reference + + + + + +

JavaScript 备忘清单

+

包含最重要概念、函数、方法等的 JavaScript 备忘单。 初学者的完整快速参考。

+

入门

+

介绍

+

JavaScript 是一种轻量级的解释型编程语言。

+ +

打印调试

+
// => Hello world!
+console.log('Hello world!');
+// => Hello QuickReference
+console.warn('hello %s', 'QuickReference');
+// 将错误消息打印到 stderr
+console.error(new Error('Oops!'));
+
+

断点调试

+
function potentiallyBuggyCode() {
+  debugger;
+  // 做可能有问题的东西来检查,逐步通过等。
+}
+
+

debugger 语句调用任何可用的调试功能。

+

数字

+
let amount = 6;
+let price = 4.99;
+let home = 1e2;
+let m = 0644;   // 八进制数字 420
+
+

let 关键字

+
let count; 
+console.log(count); // => undefined
+count = 10;
+console.log(count); // => 10
+
+

const 关键字

+
const numberOfColumns = 4;
+// TypeError: Assignment to constant...
+numberOfColumns = 8;
+
+

变量

+
let x = null;
+let name = "Tammy";
+const found = false;
+// => Tammy, false, null
+console.log(name, found, x);
+var a;
+console.log(a); // => undefined
+
+

字符串

+
let single = 'Wheres my bandit hat?';
+let double = "Wheres my bandit hat?";
+// => 21
+console.log(single.length);
+
+

算术运算符

+
5 + 5 = 10     // 加法 Addition
+10 - 5 = 5     // 加法 Subtraction
+5 * 10 = 50    // 乘法 Multiplication
+10 / 5 = 2     // 除法 Division
+10 % 5 = 0     // 取模 Modulo
+
+

注释

+
// 此行将表示注释
+/* 
+多行配置
+部署前必须更改
+以下配置。
+*/
+
+

赋值运算符

+
let number = 100;
+// 两个语句都会加 10
+number = number + 10;
+number += 10;
+console.log(number); 
+// => 120
+
+

字符串插值

+
let age = 7;
+// 字符串拼接
+'Tommy is ' + age + ' years old.';
+// 字符串插值
+`Tommy is ${age} years old.`;
+
+

字符串

+
var abc = "abcdefghijklmnopqrstuvwxyz";
+var esc = 'I don\'t \n know';    // \n 换行
+var len = abc.length;            // 字符串长度
+abc.indexOf("lmno");             // 查找子字符串,如果不包含则 -1
+abc.lastIndexOf("lmno");         // 最后一次出现
+abc.slice(3, 6);                 // 去掉“def”,负值从后面计算
+abc.replace("abc","123");        // 查找和替换,接受正则表达式
+abc.toUpperCase();               // 转换为大写
+abc.toLowerCase();               // 转换为小写
+abc.concat(" ", str2);           // abc + " " + str2
+abc.charAt(2);                   // 索引处的字符:“c”
+abc[2];                          // 不安全,abc[2] = "C" 不起作用
+// 索引处的字符代码:“c”-> 99
+abc.charCodeAt(2);            
+// 用逗号分割字符串给出一个数组
+abc.split(",");               
+// 分割字符
+abc.split("");                
+// 数字转为十六进制 (16)、八进制 (8) 或二进制 (2)
+128.toString(16);             
+
+

数字

+
var pi = 3.141;
+pi.toFixed(0);    // 返回 3             
+pi.toFixed(2);    // 返回 3.14 - 使用金钱
+pi.toPrecision(2) // 返回 3.1
+pi.valueOf();     // 返回号码
+Number(true);     // 转换为数字
+// 自 1970 年以来的毫秒数
+Number(new Date())          
+// 返回第一个数字:3
+parseInt("3 months");       
+// 返回 3.5
+parseFloat("3.5 days");     
+// 最大可能的 JS 数
+Number.MAX_VALUE            
+// 最小可能的 JS 编号
+Number.MIN_VALUE            
+// -无穷
+Number.NEGATIVE_INFINITY    
+// 无穷
+Number.POSITIVE_INFINITY    
+
+

Math

+
const pi = Math.PI; // 3.141592653589793
+Math.round(4.4);  // = 4 - 数字四舍五入
+Math.round(4.5);  // = 5
+Math.pow(2,8);    // = 256 - 2 的 8 次方    
+Math.sqrt(49);    // = 7 - 平方根
+Math.abs(-3.14);  // = 3.14 - 绝对,正值
+Math.ceil(3.14);  // = 4 - 返回 >= 最小整数
+// = 3 - 返回 <= 最大整数
+Math.floor(3.99);       
+// = 0 - 正弦
+Math.sin(0);            
+// OTHERS: tan,atan,asin,acos,余弦值
+Math.cos(Math.PI);      
+// = -2 - 最低值
+Math.min(0, 3, -2, 2);  
+// = 3 - 最高值
+Math.max(0, 3, -2, 2);  
+// = 0 自然对数
+Math.log(1);            
+// = 2.7182pow(E,x) 自然对数的底数
+Math.exp(1);            
+// 0 到 1 之间的随机数
+Math.random();          
+// 随机整数,从 1
+Math.floor(Math.random() * 5) + 1;  
+
+

全局函数

+
// 像脚本代码一样执行字符串
+eval();                     
+// 从数字返回字符串
+String(23);                 
+// 从数字返回字符串
+(23).toString();            
+// 从字符串返回数字
+Number("23");               
+// 解码 URI。 结果:“我的 page.asp”
+decodeURI(enc);             
+// 编码 URI。 结果:“my%page.asp”
+encodeURI(uri);             
+// 解码 URI 组件
+decodeURIComponent(enc);    
+// 对 URI 组件进行编码
+encodeURIComponent(uri);    
+// 是一个有限的合法数
+isFinite();                 
+// 是一个非法数字
+isNaN();                    
+// 返回字符串的浮点数
+parseFloat();               
+// 解析一个字符串并返回一个整数
+parseInt();                 
+
+

JavaScript 条件

+

操作符

+
true || false;       // true
+10 > 5 || 10 > 20;   // true
+false || false;      // false
+10 > 100 || 10 > 20; // false
+
+

逻辑运算符 &&

+
true && true;        // true
+1 > 2 && 2 > 1;      // false
+true && false;       // false
+4 === 4 && 3 > 1;    // true
+
+

比较运算符

+
1 > 3                 // false
+3 > 1                 // true
+250 >= 250            // true
+1 === 1               // true
+1 === 2               // false
+1 === '1'             // false
+
+

逻辑运算符 !

+
let lateToWork = true;
+let oppositeValue = !lateToWork;
+// => false
+console.log(oppositeValue); 
+
+

空值合并运算符 ??

+
null ?? 'I win';         //  'I win'
+undefined ?? 'Me too';   //  'Me too'
+false ?? 'I lose'        //  false
+0 ?? 'I lose again'      //  0
+'' ?? 'Damn it'          //  ''
+
+

if Statement (if 语句)

+
const isMailSent = true;
+if (isMailSent) {
+  console.log('Mail sent to recipient');
+}
+
+

Ternary Operator (三元运算符)

+
var age = 1;
+
+// => true
+var status = (age >= 18) ? true : false;
+
+

else if

+
const size = 10;
+if (size > 20) {
+  console.log('Medium');
+} else if (size > 4) {
+  console.log('Small');
+} else {
+  console.log('Tiny');
+}
+// Print: Small
+
+

== vs ===

+
0 == false     // true
+0 === false    // false, 不同类型
+1 == "1"       // true,  自动类型转换
+1 === "1"      // false, 不同类型
+null == undefined  // true
+null === undefined // false
+'0' == false       // true
+'0' === false      // false
+
+

== 只检查值,=== 检查值和类型。

+

switch 语句

+
const food = 'salad';
+
+switch (food) {
+  case 'oyster': console.log('海的味道');
+    break;
+  case 'pizza': console.log('美味的馅饼');
+    break;
+  default:
+    console.log('请您用餐');
+}
+
+

switch 多 case - 单一操作

+
const food = 'salad';
+
+switch (food) {
+  case 'oyster':
+  case 'pizza':
+    console.log('美味的馅饼');
+    break;
+  default:
+    console.log('请您用餐');
+}
+
+

JavaScript Functions 函数

+

函数

+
// 定义函数:
+function sum(num1, num2) {
+  return num1 + num2;
+}
+// 调用函数:
+sum(3, 6); // 9
+
+

匿名函数

+
// Named function
+function rocketToMars() {
+  return 'BOOM!';
+}
+// Anonymous function
+const rocketToMars = function() {
+  return 'BOOM!';
+}
+
+

箭头函数 (ES6)

+

有两个参数

+
const sum = (param1, param2) => { 
+  return param1 + param2; 
+}; 
+console.log(sum(2,5)); // => 7 
+
+

没有参数

+
const printHello = () => { 
+  console.log('hello'); 
+}; 
+printHello(); // => hello
+
+

只有一个参数

+
const checkWeight = weight => { 
+  console.log(`Weight : ${weight}`); 
+}; 
+checkWeight(25); // => Weight : 25 
+
+

简洁箭头函数

+
const multiply = (a, b) => a * b; 
+// => 60 
+console.log(multiply(2, 30)); 
+
+

从 ES2015 开始提供箭头函数

+

返回关键字

+
// 有 return
+function sum(num1, num2) {
+  return num1 + num2;
+}
+// 该函数不输出总和
+function sum(num1, num2) {
+  num1 + num2;
+}
+
+

调用函数

+
// 定义函数
+function sum(num1, num2) {
+  return num1 + num2;
+}
+// 调用函数
+sum(2, 4); // 6
+
+

函数表达式

+
const dog = function() {
+  return 'Woof!';
+}
+
+

函数参数

+
// 参数是 name
+function sayHello(name) {
+  return `Hello, ${name}!`;
+}
+
+

函数声明

+
function add(num1, num2) {
+  return num1 + num2;
+}
+
+

JavaScript 范围

+

范围

+
function myFunction() {
+  
+  var pizzaName = "Margarita";
+  // 这里的代码可以使用 PizzaName
+  
+}
+// 这里的代码不能使用 PizzaName
+
+

Block Scoped Variables

+
const isLoggedIn = true;
+if (isLoggedIn == true) {
+  const statusMessage = 'Logged in.';
+}
+// Uncaught ReferenceError...
+// 未捕获的引用错误...
+console.log(statusMessage);
+
+

全局变量

+
// 全局声明的变量
+const color = 'blue';
+function printColor() {
+  console.log(color);
+}
+printColor(); // => blue
+
+

let vs var

+
for (let i = 0; i < 3; i++) {
+  // 这是“let”的最大范围
+  // i 可以访问 ✔️
+}
+// i 不能访问 ❌
+
+
+
for (var i = 0; i < 3; i++) {
+  // i 可以访问 ✔️
+}
+// i 可以访问 ✔️
+
+

var 的范围是最近的函数块,而 let 的范围是最近的封闭块。

+

带闭包的循环

+
// 打印三次,不是我们的意思。
+for (var i = 0; i < 3; i++) {
+  setTimeout(_ => console.log(i), 10);
+}
+
+
+
// 按预期打印 0、1 和 2。
+for (let j = 0; j < 3; j++) { 
+  setTimeout(_ => console.log(j), 10);
+}
+
+

变量使用 let 有自己的副本,变量有使用 var 的共享副本。

+

JavaScript Arrays

+

数组

+
const fruits = ["apple", "dew", "banana"];
+// 不同的数据类型
+const data = [1, 'chicken', false];
+
+

属性 .length

+
const numbers = [1, 2, 3, 4];
+numbers.length // 4
+
+

索引

+
// 访问数组元素
+const myArray = [100, 200, 300];
+console.log(myArray[0]); // 100
+console.log(myArray[1]); // 200
+
+

可变图表

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
添加删除开始结束
push
pop
unshift
shift
+

方法 .push()

+
// 添加单个元素:
+const cart = ['apple', 'orange'];
+cart.push('pear'); 
+// 添加多个元素:
+const numbers = [1, 2];
+numbers.push(3, 4, 5);
+
+

将项目添加到末尾并返回新的数组长度。

+

方法 .pop()

+
const fruits = ["apple", "dew", "banana"];
+const fruit = fruits.pop(); // 'banana'
+
+console.log(fruits); // ["apple", "dew"]
+
+

末尾删除一个项目并返回已删除的项目。

+

方法 .shift()

+
let cats = ['Bob', 'Willy', 'Mini'];
+cats.shift(); // ['Willy', 'Mini']
+
+

从头删除一个项目并返回已删除的项目。

+

方法 .unshift()

+
let cats = ['Bob'];
+// => ['Willy', 'Bob']
+cats.unshift('Willy');
+// => ['Puff', 'George', 'Willy', 'Bob']
+cats.unshift('Puff', 'George');
+
+

将项目添加到开头并返回新的数组长度。

+

方法 .concat()

+
const numbers = [3, 2, 1]
+const newFirstNumber = 4
+    
+// => [ 4, 3, 2, 1 ]
+[newFirstNumber].concat(numbers)
+    
+// => [ 3, 2, 1, 4 ]
+numbers.concat(newFirstNumber)
+
+

如果你想避免改变你的原始数组,你可以使用 concat。

+

JavaScript 循环

+

While 循环

+
while (condition) {
+  // 要执行的代码块
+}
+let i = 0;
+while (i < 5) {        
+  console.log(i);
+  i++;
+}
+
+

反向循环

+
const fruits = ["apple", "dew", "berry"];
+for (let i = fruits.length - 1; i >= 0; i--) {
+  console.log(`${i}. ${fruits[i]}`);
+}
+// => 2. berry
+// => 1. dew
+// => 0. apple
+
+

Do...While 语句

+
x = 0
+i = 0
+do {
+  x = x + i;
+  console.log(x)
+  i++;
+} while (i < 5);
+// => 0 1 3 6 10
+
+

For 循环

+
for (let i = 0; i < 4; i += 1) {
+  console.log(i);
+};
+// => 0, 1, 2, 3
+
+

遍历数组

+
for (let i = 0; i < array.length; i++){
+  console.log(array[i]);
+}
+// => 数组中的每一项
+
+

Break

+
for (let i = 0; i < 99; i += 1) {
+  if (i > 5) {
+     break;
+  }
+  console.log(i)
+}
+// => 0 1 2 3 4 5
+
+

Continue

+
for (i = 0; i < 10; i++) {
+  if (i === 3) {
+    continue;
+  }
+  text += "The number is " + i + "<br>";
+}
+
+

嵌套循环

+
for (let i = 0; i < 2; i += 1) {
+  for (let j = 0; j < 3; j += 1) {
+    console.log(`${i}-${j}`);
+  }
+}
+
+

for...in 循环

+
const fruits = ["apple", "orange", "banana"];
+for (let index in fruits) {
+  console.log(index);
+}
+// => 0
+// => 1
+// => 2
+
+

label 语句

+
var num = 0;
+
+outPoint:
+for(var i = 0; i < 10; i++) {
+  for(var j = 0; j < 10; j++) {
+    if(i == 5 && j == 5) {
+      continue outPoint;
+    }
+    num++;
+  }
+}
+
+alert(num);  // 95
+
+

alert(num) 的值可以看出,continue outPoint; 语句的作用是跳出当前循环,并跳转到 outPoint(标签)下的 for 循环继续执行。

+

for...of 循环

+
const fruits = ["apple", "orange", "banana"];
+for (let fruit of fruits) {
+  console.log(fruit);
+}
+// => apple
+// => orange
+// => banana
+
+

for await...of

+
async function* asyncGenerator() {
+  var i = 0;
+  while (i < 3) {
+    yield i++;
+  }
+}
+
+(async function() {
+  for await (num of asyncGenerator()) {
+    console.log(num);
+  }
+})();
+
+// 0
+// 1
+// 2
+
+

可选的 for 表达式

+
var i = 0;
+
+for (;;) {
+  if (i > 3) break;
+  console.log(i);
+  i++;
+}
+
+

JavaScript 迭代器(Iterators)

+

分配给变量的函数

+
let plusFive = (number) => {
+  return number + 5;  
+};
+// f 被赋值为 plusFive
+let f = plusFive;
+plusFive(3); // 8
+// 由于 f 具有函数值,因此可以调用它。
+f(9); // 14
+
+

回调函数

+
const isEven = (n) => {
+  return n % 2 == 0;
+}
+let printMsg = (evenFunc, num) => {
+  const isNumEven = evenFunc(num);
+  console.log(`${num} is an even number: ${isNumEven}.`)
+}
+// Pass in isEven as the callback function
+printMsg(isEven, 4); 
+// => The number 4 is an even number: True.
+
+

数组方法 .reduce()

+
const numbers = [1, 2, 3, 4];
+const sum = numbers.reduce((accumulator, curVal) => {  
+  return accumulator + curVal;
+});
+console.log(sum); // 10
+
+

数组方法 .map()

+
const members = ["Taylor", "Donald", "Don", "Natasha", "Bobby"];
+const announcements = members.map((member) => {
+  return member + " joined the contest.";
+});
+console.log(announcements);
+
+

数组方法 .forEach()

+
const numbers = [28, 77, 45, 99, 27];
+numbers.forEach(number => {  
+  console.log(number);
+}); 
+
+

数组方法 .filter()

+
const randomNumbers = [4, 11, 42, 14, 39];
+const filteredArray = randomNumbers.filter(n => {  
+  return n > 5;
+});
+
+

JavaScript 对象(Objects)

+

访问属性

+
const apple = { 
+  color: 'Green',
+  price: { bulk: '$3/kg', smallQty: '$4/kg' }
+};
+console.log(apple.color);      // => Green
+console.log(apple.price.bulk); // => $3/kg
+
+

命名属性

+
// 无效键名示例
+const trainSchedule = {
+  // 由于单词之间的空格而无效。
+  platform num: 10, 
+  // 表达式不能是键。
+  40 - 10 + 2: 30,
+  // 除非用引号括起来,否则 + 号无效。
+  +compartment: 'C'
+}
+
+

不存在的属性

+
const classElection = {
+  date: 'January 12'
+};
+console.log(classElection.place); // undefined
+
+

可变的

+
const student = {
+  name: 'Sheldon',
+  score: 100,
+  grade: 'A',
+}
+console.log(student)
+// { name: 'Sheldon', score: 100, grade: 'A' }
+delete student.score
+student.grade = 'F'
+console.log(student)
+// { name: 'Sheldon', grade: 'F' }
+student = {}
+// TypeError: TypeError:分配给常量变量。
+
+

赋值简写语法

+
const person = {
+  name: 'Tom',
+  age: '22',
+};
+const {name, age} = person;
+console.log(name); // 'Tom'
+console.log(age);  // '22'
+
+

删除运算符

+
const person = {
+  firstName: "Matilda",
+  age: 27,
+  hobby: "knitting",
+  goal: "learning JavaScript"
+};
+delete person.hobby; // or delete person[hobby];
+console.log(person);
+/*
+{
+  firstName: "Matilda"
+  age: 27
+  goal: "learning JavaScript"
+}
+*/
+
+

对象作为参数

+
const origNum = 8;
+const origObj = {color: 'blue'};
+const changeItUp = (num, obj) => {
+  num = 7;
+  obj.color = 'red';
+};
+changeItUp(origNum, origObj);
+// 将输出 8,因为整数是按值传递的。
+console.log(origNum);
+// 由于传递了对象,将输出“red”
+// 通过引用,因此是可变的。
+console.log(origObj.color);
+
+

工厂函数

+
// 一个接受 'name','age' 和 'breed' 的工厂函数,
+//  参数返回一个自定义的 dog 对象。
+const dogFactory = (name, age, breed) => {
+  return {
+    name: name,
+    age: age,
+    breed: breed,
+    bark() {
+      console.log('Woof!');  
+    }
+  };
+};
+
+

速记对象创建

+
const activity = 'Surfing';
+const beach = { activity };
+console.log(beach); // { activity: 'Surfing' }
+
+

this 关键字

+
const cat = {
+  name: 'Pipey',
+  age: 8,
+  whatName() {
+    return this.name  
+  }
+};
+console.log(cat.whatName()); // => Pipey
+
+

方法

+
const engine = {
+  // 方法简写,有一个参数
+  start(adverb) {
+    console.log(`The engine starts up ${adverb}...`);
+  },  
+  // 不带参数的匿名箭头函数表达式
+  sputter: () => {
+    console.log('The engine sputters...');
+  },
+};
+engine.start('noisily');
+engine.sputter();
+
+

Getters 和 setters

+
const myCat = {
+  _name: 'Dottie',
+  get name() {
+    return this._name;  
+  },
+  set name(newName) {
+    this._name = newName;  
+  }
+};
+// 引用调用 getter
+console.log(myCat.name);
+// 赋值调用 setter
+myCat.name = 'Yankee';
+
+

JavaScript Classes

+

静态方法/字段

+
class Dog {
+  constructor(name) {
+    this._name = name;  
+  }
+  
+  introduce() { 
+    console.log('This is ' + this._name + ' !');  
+  }
+  
+  // 静态方法
+  static bark() {
+    console.log('Woof!');  
+  }
+
+  static {
+    console.log('类静态初始化块调用');
+  }
+}
+
+const myDog = new Dog('Buster');
+myDog.introduce();
+
+// 调用静态方法
+Dog.bark();
+
+

公有静态字段

+
class ClassStaticField {
+  static staticField = 'static field'
+}
+
+console.log(ClassStaticField.staticField)
+// 预期输出值:"static field"​ 
+
+

Class

+
class Song {
+  constructor() {
+    this.title;
+    this.author;
+  }
+  
+  play() {
+    console.log('Song playing!');
+  }
+}
+
+const mySong = new Song();
+mySong.play();
+
+

extends

+
// Parent class
+class Media {
+  constructor(info) {
+    this.publishDate = info.publishDate;
+    this.name = info.name;
+  }
+}
+// Child class
+class Song extends Media {
+  constructor(songData) {
+    super(songData);
+    this.artist = songData.artist;
+  }
+}
+const mySong = new Song({ 
+  artist: 'Queen', 
+  name: 'Bohemian Rhapsody', 
+  publishDate: 1975
+});
+
+

Class Constructor

+
class Song {
+  constructor(title, artist) {
+    this.title = title;
+    this.artist = artist;
+  }
+}
+const mySong = new Song('Bohemian Rhapsody', 'Queen');
+console.log(mySong.title);
+
+

Class Methods

+
class Song {
+  play() {
+    console.log('Playing!');
+  }
+  
+  stop() {
+    console.log('Stopping!');
+  }
+}
+
+

JavaScript Modules

+

Export / Import

+
// myMath.js
+// 默认导出 Default export
+export default function add(x,y){
+  return x + y
+}
+// 正常导出 Normal export
+export function subtract(x,y){
+  return x - y
+}
+// 多重导出 Multiple exports
+function multiply(x,y){
+  return x * y
+}
+function duplicate(x){
+  return x * 2
+}
+export {
+  multiply, duplicate
+}
+
+

import 加载模块

+
// main.js
+import add, { subtract, multiply, duplicate } from './myMath.js';
+console.log(add(6, 2));      // 8 
+console.log(subtract(6, 2))  // 4
+console.log(multiply(6, 2)); // 12
+console.log(duplicate(5))    // 10
+// index.html
+<script type="module" src="main.js"></script>
+
+

Export Module

+
// myMath.js
+function add(x,y){
+  return x + y
+}
+function subtract(x,y){
+  return x - y
+}
+function multiply(x,y){
+  return x * y
+}
+function duplicate(x){
+  return x * 2
+}
+// node.js 中的多个导出
+module.exports = {
+  add,
+  subtract,
+  multiply,
+  duplicate
+}
+
+

require 加载模块

+
// main.js
+const myMath = require('./myMath.js')
+console.log(myMath.add(6, 2));      // 8 
+console.log(myMath.subtract(6, 2))  // 4
+console.log(myMath.multiply(6, 2)); // 12
+console.log(myMath.duplicate(5))    // 10
+
+

JavaScript Promises

+

Promise 状态

+
const promise = new Promise((resolve, reject) => {
+  const res = true;
+  // An asynchronous operation.
+  if (res) {
+    resolve('Resolved!');
+  }
+  else {
+    reject(Error('Error'));
+  }
+});
+promise.then((res) => console.log(res), (err) => console.error(err));
+
+

执行器函数

+
const executorFn = (resolve, reject) => {
+  resolve('Resolved!');
+};
+const promise = new Promise(executorFn);
+
+

setTimeout()

+
const loginAlert = () =>{
+  console.log('Login');
+};
+setTimeout(loginAlert, 6000);
+
+

.then() 方法

+
const promise = new Promise((resolve, reject) => {    
+  setTimeout(() => {
+    resolve('Result');
+  }, 200);
+});
+promise.then((res) => {
+  console.log(res);
+}, (err) => {
+  console.error(err);
+});
+
+

.catch() 方法

+
const promise = new Promise((resolve, reject) => {  
+  setTimeout(() => {
+    reject(Error('Promise Rejected Unconditionally.'));
+  }, 1000);
+});
+promise.then((res) => {
+  console.log(value);
+});
+promise.catch((err) => {
+  console.error(err);
+});
+
+

Promise.all()

+
const promise1 = new Promise((resolve, reject) => {
+  setTimeout(() => {
+    resolve(3);
+  }, 300);
+});
+const promise2 = new Promise((resolve, reject) => {
+  setTimeout(() => {
+    resolve(2);
+  }, 200);
+});
+Promise.all([promise1, promise2]).then((res) => {
+  console.log(res[0]);
+  console.log(res[1]);
+});
+
+

避免嵌套的 Promise 和 .then()

+
const promise = new Promise((resolve, reject) => {  
+  setTimeout(() => {
+    resolve('*');
+  }, 1000);
+});
+const twoStars = (star) => {  
+  return (star + star);
+};
+const oneDot = (star) => {  
+  return (star + '.');
+};
+const print = (val) => {
+  console.log(val);
+};
+// 将它们链接在一起
+promise.then(twoStars).then(oneDot).then(print);
+
+

创建

+
const executorFn = (resolve, reject) => {
+  console.log('The executor function of the promise!');
+};
+const promise = new Promise(executorFn);
+
+

链接多个 .then()

+
const promise = new Promise(resolve => setTimeout(() => resolve('dAlan'), 100));
+promise.then(res => {
+  return res === 'Alan' ? Promise.resolve('Hey Alan!') : Promise.reject('Who are you?')
+}).then((res) => {
+  console.log(res)
+}, (err) => {
+  console.error(err)
+});
+
+

JavaScript Async-Await

+

异步

+
function helloWorld() {
+  return new Promise(resolve => {
+    setTimeout(() => {
+      resolve('Hello World!');
+    }, 2000);
+  });
+}
+const msg = async function() { // 异步函数表达式
+  const msg = await helloWorld();
+  console.log('Message:', msg);
+}
+const msg1 = async () => { // 异步箭头函数
+  const msg = await helloWorld();
+  console.log('Message:', msg);
+}
+msg(); // Message: Hello World! <-- 2 秒后
+msg1(); // Message: Hello World! <-- 2 秒后
+
+

解决 Promises

+
let pro1 = Promise.resolve(5);
+let pro2 = 44;
+let pro3 = new Promise(function(resolve, reject) {
+  setTimeout(resolve, 100, 'foo');
+});
+Promise.all([pro1, pro2, pro3]).then(function(values) {
+  console.log(values);
+});
+// expected => Array [5, 44, "foo"]
+
+

异步等待 Promises

+
function helloWorld() {
+  return new Promise(resolve => {
+    setTimeout(() => {
+      resolve('Hello World!');
+    }, 2000);
+  });
+}
+async function msg() {
+  const msg = await helloWorld();
+  console.log('Message:', msg);
+}
+msg(); // Message: Hello World! <-- 2 秒后
+
+

错误处理

+
let json = '{ "age": 30 }'; // 数据不完整
+try {
+  let user = JSON.parse(json); // <-- 没有错误
+  console.log( user.name ); // no name!
+} catch (e) {
+  console.error( "Invalid JSON data!" );
+}
+
+

异步等待运算符

+
function helloWorld() {
+  return new Promise(resolve => {
+    setTimeout(() => {
+      resolve('Hello World!');
+    }, 2000);
+  });
+}
+async function msg() {
+  const msg = await helloWorld();
+  console.log('Message:', msg);
+}
+msg(); // Message: Hello World! <-- 2 秒后
+
+

JavaScript 请求

+

JSON

+
const jsonObj = {
+  "name": "Rick",
+  "id": "11A",
+  "level": 4  
+};
+
+

另见:JSON 备忘单

+

XMLHttpRequest

+
const xhr = new XMLHttpRequest();
+xhr.open('GET', 'mysite.com/getjson');
+
+

XMLHttpRequest 是一个浏览器级别的 API,它使客户端能够通过 JavaScript 编写数据传输脚本,而不是 JavaScript 语言的一部分。

+

GET

+
const req = new XMLHttpRequest();
+req.responseType = 'json';
+req.open('GET', '/getdata?id=65');
+req.onload = () => {
+  console.log(xhr.response);
+};
+req.send();
+
+

POST

+
const data = {
+  fish: 'Salmon',
+  weight: '1.5 KG',
+  units: 5
+};
+const xhr = new XMLHttpRequest();
+xhr.open('POST', '/inventory/add');
+xhr.responseType = 'json';
+xhr.send(JSON.stringify(data));
+xhr.onload = () => {
+  console.log(xhr.response);
+};
+
+

fetch api

+
fetch(url, {
+    method: 'POST',
+    headers: {
+      'Content-type': 'application/json',
+      'apikey': apiKey
+    },
+    body: data
+  }).then(response => {
+    if (response.ok) {
+      return response.json();
+    }
+    throw new Error('Request failed!');
+  }, networkError => {
+    console.log(networkError.message)
+  })
+}
+
+

JSON 格式

+
fetch('url-that-returns-JSON')
+.then(response => response.json())
+.then(jsonResponse => {
+  console.log(jsonResponse);
+});
+
+

promise url 参数获取 API

+
fetch('url')
+.then(
+  response  => {
+    console.log(response);
+  },
+ rejection => {
+    console.error(rejection.message);
+);
+
+

Fetch API 函数

+
fetch('https://api-xxx.com/endpoint', {
+  method: 'POST',
+  body: JSON.stringify({id: "200"})
+}).then(response => {
+  if(response.ok){
+	  return response.json();  
+  }
+	throw new Error('Request failed!');
+}, networkError => {
+  console.log(networkError.message);
+}).then(jsonResponse => {
+  console.log(jsonResponse);
+})
+
+

async await 语法

+
const getSuggestions = async () => {
+  const wordQuery = inputField.value;
+  const endpoint = `${url}${queryParams}${wordQuery}`;
+  try{
+    const response = await fetch(endpoint, {cache: 'no-cache'});
+    if(response.ok){
+      const jsonResponse = await response.json()
+    }
+  }
+  catch(error){
+    console.log(error)
+  }
+}
+
+ +
+ diff --git a/docs/jest.html b/docs/jest.html new file mode 100644 index 00000000..09ecfeb6 --- /dev/null +++ b/docs/jest.html @@ -0,0 +1,520 @@ + + + + +Jest 备忘清单 + & Quick Reference + + + + + +

Jest 备忘清单

+

Jest 是一款优雅、简洁的 JavaScript 测试框架。

+

入门

+

介绍

+

Jest 是一款优雅、简洁的 JavaScript 测试框架。

+
    +
  • 无需配置,大多数 JS 项目中即装即用,无需配置
  • +
  • 优秀接口,从 it 到 expect - Jest 将工具包整合在一处。文档齐全、不断维护,非常不错。
  • +
  • 隔离的,并行进行测试,发挥每一丝算力。
  • +
  • 快照, 轻松编写持续追踪大型对象的测试,并在测试旁或代码内显示实时快照。
  • +
  • 代码覆盖, 无需其他操作,您仅需添加 --coverage 参数来生成代码覆盖率报告。
  • +
+

测试结构

+
describe('makePoniesPink', () => {
+  beforeAll(() => {
+    /* 在所有测试之前运行 */
+  })
+  afterAll(() => {
+    /* 在所有测试后运行 */
+  })
+  beforeEach(() => {
+    /* 在每次测试之前运行 */
+  })
+  afterEach(() => {
+    /* 每次测试后运行 */
+  })
+  test('make each pony pink', () => {
+    const actual = fn(['Alice', 'Bob', 'Eve'])
+    expect(actual).toEqual(['Pink Alice', 'Pink Bob', 'Pink Eve'])
+  })
+})
+
+

匹配器

+

基本匹配器

+
expect(42).toBe(42)    // 严格相等 (===)
+expect(42).not.toBe(3) // 严格相等 (!==)
+expect([1, 2]).toEqual([1, 2]) // 深度相等
+
+// 深度相等
+expect({ a: undefined, b: 2 })
+  .toEqual({ b: 2 })
+
+// 严格相等 (Jest 23+)
+expect({ a: undefined, b: 2 })
+  .not.toStrictEqual({ b: 2 })
+
+

Using matchers, matchers docs

+

真实性

+
// 匹配 if 语句视为 true 的任何内容
+// (not false、0、''、null、undefined、NaN)
+expect('foo').toBeTruthy()
+// 匹配 if 语句视为 false 的任何内容
+// (false、0、''、null、undefined、NaN)
+expect('').toBeFalsy()
+// 仅匹配 null
+expect(null).toBeNull()
+// 仅匹配未定义
+expect(undefined).toBeUndefined()
+// toBeUndefined 的反义词
+expect(7).toBeDefined()
+// 匹配真假
+expect(true).toEqual(expect.any(Boolean))
+
+

数字

+
// 大于
+expect(2).toBeGreaterThan(1)
+// 大于或等于
+expect(1).toBeGreaterThanOrEqual(1)
+// 小于
+expect(1).toBeLessThan(2)
+// 小于或等于
+expect(1).toBeLessThanOrEqual(1)
+// 接近于
+expect(0.2 + 0.1).toBeCloseTo(0.3, 5)
+// 原始值的传递类型
+expect(NaN).toEqual(expect.any(Number))
+
+

字符串

+
// 检查字符串是否与正则表达式匹配。
+expect('long string').toMatch('str')
+expect('string').toEqual(expect.any(String))
+expect('coffee').toMatch(/ff/)
+expect('pizza').not.toMatch('coffee')
+expect(['pizza', 'coffee']).toEqual(
+  [
+    expect.stringContaining('zz'), 
+    expect.stringMatching(/ff/)
+  ]
+)
+
+

数组

+
expect([]).toEqual(expect.any(Array))
+const exampleArray = [
+  'Alice', 'Bob', 'Eve'
+]
+expect(exampleArray).toHaveLength(3)
+expect(exampleArray).toContain('Alice')
+expect(exampleArray).toEqual(
+  expect.arrayContaining(['Alice', 'Bob'])
+)
+expect([{ a: 1 }, { a: 2 }])
+    .toContainEqual({ a: 1 }) // 包含相等
+
+

对象

+
expect({ a:1 }).toHaveProperty('a')
+expect({ a:1 }).toHaveProperty('a', 1)
+expect({ a: {b:1} }).toHaveProperty('a.b')
+expect({ a:1, b:2 }).toMatchObject({a:1})
+expect({ a:1, b:2 }).toMatchObject({
+  a: expect.any(Number),
+  b: expect.any(Number),
+})
+expect([{ a: 1 }, { b: 2 }]).toEqual([
+  expect.objectContaining(
+    { a: expect.any(Number) }
+  ),
+  expect.anything(),
+])
+
+

模拟函数

+
// const fn = jest.fn()
+// const fn = jest.fn().mockName('Unicorn') -- 命名为 mock, Jest 22+
+// 函数被调用
+expect(fn).toBeCalled()
+// 函数*未*调用
+expect(fn).not.toBeCalled()
+// 函数只被调用一次
+expect(fn).toHaveBeenCalledTimes(1)
+// 任何执行都带有这些参数
+expect(fn).toBeCalledWith(arg1, arg2)
+// 最后一个执行是用这些参数
+expect(fn).toHaveBeenLastCalledWith(arg1, arg2)
+// 第 N 个执行带有这些参数(Jest 23+)
+expect(fn).toHaveBeenNthCalledWith(callNumber, args)
+// 函数返回没有抛出错误(Jest 23+)
+expect(fn).toHaveReturnedTimes(2)
+// 函数返回一个值(Jest 23+)
+expect(fn).toHaveReturnedWith(value)
+// 最后一个函数调用返回一个值(Jest 23+)
+expect(fn).toHaveLastReturnedWith(value)
+// 第 N 个函数调用返回一个值(Jest 23+)
+expect(fn).toHaveNthReturnedWith(value)
+expect(fn.mock.calls).toEqual([
+  ['first', 'call', 'args'],
+  ['second', 'call', 'args'],
+]) // 多次调用
+// fn.mock.calls[0][0] — 第一次调用的第一个参数
+expect(fn.mock.calls[0][0]).toBe(2)
+
+

别名

+
    +
  • toBeCalledtoHaveBeenCalled
  • +
  • toBeCalledWithtoHaveBeenCalledWith
  • +
  • lastCalledWithtoHaveBeenLastCalledWith
  • +
  • nthCalledWithtoHaveBeenNthCalledWith
  • +
  • toReturnTimestoHaveReturnedTimes
  • +
  • toReturnWithtoHaveReturnedWith
  • +
  • lastReturnedWithtoHaveLastReturnedWith
  • +
  • nthReturnedWithtoHaveNthReturnedWith
  • +
+

杂项

+
// 检查对象是否是类的实例。
+expect(new A()).toBeInstanceOf(A)
+
+// 检查对象是否是函数的实例。
+expect(() => {}).toEqual(
+  expect.any(Function)
+)
+
+// 匹配除 null 或 undefined 之外的任何内容
+expect('pizza').toEqual(expect.anything())
+
+

快照

+
// 这可确保某个值与最近的快照匹配。
+expect(node).toMatchSnapshot()
+
+// Jest 23+
+expect(user).toMatchSnapshot({
+  date: expect.any(Date),
+})
+
+// 确保值与最近的快照匹配。
+expect(user).toMatchInlineSnapshot()
+
+

Promise 匹配器(Jest 20+)

+
test('resolve to lemon', () => {
+  // 验证在测试期间是否调用了一定数量的断言。
+  expect.assertions(1)
+  // 确保添加return语句
+  return expect(Promise.resolve('lemon'))
+            .resolves.toBe('lemon')
+
+  return expect(Promise.reject('octopus'))
+            .rejects.toBeDefined()
+
+  return expect(Promise.reject(
+    Error('pizza')
+  )).rejects.toThrow()
+})
+
+

或者使用 async/await:

+
test('resolve to lemon', async () => {
+  expect.assertions(2)
+  await expect(Promise.resolve('lemon'))
+          .resolves.toBe('lemon')
+
+  await expect(Promise.resolve('lemon'))
+          .resolves.not.toBe('octopus')
+})
+
+

resolves 文档

+

例外

+
// const fn = () => {
+//    throw new Error('Out of cheese!')
+// }
+
+expect(fn).toThrow()
+expect(fn).toThrow('Out of cheese')
+
+// 测试错误消息在某处说“cheese”:这些是等价的
+expect(fn).toThrowError(/cheese/);
+expect(fn).toThrowError('cheese');
+
+// 测试准确的错误信息
+expect(fn).toThrowError(
+  /^Out of cheese!$/
+);
+expect(fn).toThrowError(
+  new Error('Out of cheese!')
+);
+
+// 测试函数在调用时是否抛出与最新快照匹配的错误。
+expect(fn).toThrowErrorMatchingSnapshot()
+
+

别名

+
    +
  • toThrowErrortoThrow
  • +
+

异步测试

+

实例

+

请参阅 Jest 文档中的 更多示例

+

在异步测试中指定一些预期的断言是一个很好的做法,所以如果你的断言根本没有被调用,测试将会失败。

+
test('async test', () => {
+  // 在测试期间恰好调用了三个断言
+  expect.assertions(3) 
+  // 或者 - 在测试期间至少调用一个断言
+  expect.hasAssertions()
+  // 你的异步测试
+})
+
+

请注意,您也可以在任何 describetest 之外对每个文件执行此操作:

+
beforeEach(expect.hasAssertions)
+
+

这将验证每个测试用例至少存在一个断言。 它还可以与更具体的 expect.assertions(3) 声明配合使用。

+

async/await

+
test('async test', async () => {
+  expect.assertions(1)
+
+  const result = await runAsyncOperation()
+  expect(result).toBe(true)
+})
+
+

done() 回调

+
test('async test', (done) => {
+  expect.assertions(1)
+
+  runAsyncOperation()
+  
+  setTimeout(() => {
+    try {
+      const result = getAsyncOperationResult()
+      expect(result).toBe(true)
+      done()
+    } catch (err) {
+      done.fail(err)
+    }
+  })
+})
+
+

将断言包装在 try/catch 块中,否则 Jest 将忽略失败

+

Promises

+
test('async test', () => {
+  expect.assertions(1)
+
+  return runAsyncOperation().then((result) => {
+    expect(result).toBe(true)
+  })
+})
+
+

从你的测试中 返回 一个 Promise

+

模拟

+

模拟函数

+
test('call the callback', () => {
+  const callback = jest.fn()
+  fn(callback)
+  expect(callback).toBeCalled()
+  expect(callback.mock.calls[0][1].baz).toBe('pizza') // 第一次调用的第二个参数
+  // 匹配第一个和最后一个参数,但忽略第二个参数
+  expect(callback).toHaveBeenLastCalledWith('meal', expect.anything(), 'margarita')
+})
+
+

您还可以使用快照:

+
test('call the callback', () => {
+  // mockName 在 Jest 22+ 中可用
+  const callback = jest.fn().mockName('Unicorn') 
+  fn(callback)
+  expect(callback).toMatchSnapshot()
+  // ->
+  // [MockFunction Unicorn] {
+  //   "calls": Array [
+  // ...
+})
+
+

并将实现传递给 jest.fn 函数:

+
const callback = jest.fn(() => true)
+
+

模拟函数文档

+

返回、解析和拒绝值

+

您的模拟可以返回值:

+
const callback
+    = jest.fn().mockReturnValue(true)
+const callbackOnce
+    = jest.fn().mockReturnValueOnce(true)
+
+

或解析值:

+
const promise 
+    = jest.fn().mockResolvedValue(true)
+const promiseOnce 
+    = jest.fn().mockResolvedValueOnce(true)
+
+

他们甚至可以拒绝值:

+
const failedPromise
+    = jest.fn().mockRejectedValue('Error')
+const failedPromiseOnce
+    = jest.fn().mockRejectedValueOnce('Error')
+
+

你甚至可以结合这些:

+
const callback
+    = jest.fn().mockReturnValueOnce(false).mockReturnValue(true)
+// ->
+//  call 1: false
+//  call 2+: true
+
+

使用 jest.mock 方法模拟模块

+
jest.mock('lodash/memoize', () => (a) => a) // The original lodash/memoize should exist
+jest.mock('lodash/memoize', () => (a) => a, { virtual: true }) // The original lodash/memoize isn’t required
+
+

jest.mock docs

+
+

注意:当使用 babel-jest 时,对 jest.mock 的调用将自动提升到代码块的顶部。 如果您想明确避免这种行为,请使用 jest.doMock

+
+

使用模拟文件模拟模块

+

创建一个类似 __mocks__/lodash/memoize.js 的文件:

+
module.exports = (a) => a
+
+

添加到您的测试中:

+
jest.mock('lodash/memoize')
+
+

注意:当使用 babel-jest 时,对 jest.mock 的调用将自动提升到代码块的顶部。 如果您想明确避免这种行为,请使用 jest.doMock

+

手动模拟文档

+

模拟对象方法

+
const spy = jest.spyOn(console, 'log').mockImplementation(() => {})
+expect(console.log.mock.calls).toEqual([['dope'], ['nope']])
+spy.mockRestore()
+
+
const spy = jest.spyOn(ajax, 'request').mockImplementation(() => Promise.resolve({ success: true }))
+expect(spy).toHaveBeenCalled()
+spy.mockRestore()
+
+

模拟 getter 和 setter (Jest 22.1.0+)

+
const location = {}
+const getTitle = jest
+    .spyOn(location, 'title', 'get')
+    .mockImplementation(() => 'pizza')
+const setTitle = jest
+    .spyOn(location, 'title', 'set')
+    .mockImplementation(() => {})
+
+

定时器模拟

+

为使用本机计时器函数(setTimeoutsetIntervalclearTimeoutclearInterval)的代码编写同步测试。

+
// 启用假计时器
+jest.useFakeTimers()
+test('kill the time', () => {
+  const callback = jest.fn()
+  // 运行一些使用 setTimeout 或 setInterval 的代码
+  const actual = someFunctionThatUseTimers(callback)
+  // 快进直到所有定时器都执行完毕
+  jest.runAllTimers()
+  // 同步检查结果
+  expect(callback).toHaveBeenCalledTimes(1)
+})
+
+

或者使用 advanceTimersByTime() 按时间调整计时器:

+
// 启用假计时器
+jest.useFakeTimers()
+test('kill the time', () => {
+  const callback = jest.fn()
+  // 运行一些使用 setTimeout 或 setInterval 的代码
+  const actual = someFunctionThatUseTimers(callback)
+  // 快进 250 毫秒
+  jest.advanceTimersByTime(250)
+  // 同步检查结果
+  expect(callback).toHaveBeenCalledTimes(1)
+})
+
+

对于特殊情况,请使用 jest.runOnlyPendingTimers()

+

注意: 您应该在测试用例中调用 jest.useFakeTimers() 以使用其他假计时器方法。

+

模拟 getters 和 setters

+
const getTitle = jest.fn(() => 'pizza')
+const setTitle = jest.fn()
+const location = {}
+Object.defineProperty(location, 'title', {
+  get: getTitle,
+  set: setTitle,
+})
+
+

清除和恢复模拟

+

对于一个模拟

+
// 清除模拟使用日期
+// (fn.mock.calls、fn.mock.instances)
+fn.mockClear()
+// 清除并删除任何模拟的返回值或实现
+fn.mockReset()
+// 重置并恢复初始实现
+fn.mockRestore()
+
+
+

注意:mockRestore 仅适用于由jest.spyOn 创建的模拟。对于所有模拟:

+
+
// 清除所有 mock 的 
+// mock.calls、mock.instances、
+// mock.contexts 和 mock.results 属性。
+jest.clearAllMocks()
+// 重置所有模拟的状态。
+jest.resetAllMocks()
+// 将所有模拟恢复到其原始值。
+jest.restoreAllMocks()
+
+

使用模拟时访问原始模块

+
jest.mock('fs')
+// 模拟模块
+const fs = require('fs')
+// 原始模块
+const fs = require.requireActual('fs')
+
+

数据驱动测试(Jest 23+)

+

使用不同的数据运行相同的测试

+
test.each([
+  [1, 1, 2],
+  [1, 2, 3],
+  [2, 1, 3],
+])('.add(%s, %s)', (a, b, expected) => {
+  expect(a + b).toBe(expected)
+})
+
+

使用模板文字相同

+
test.each`
+  a    | b    | expected
+  ${1} | ${1} | ${2}
+  ${1} | ${2} | ${3}
+  ${2} | ${1} | ${3}
+`('returns $expected when $a is added $b', ({ a, b, expected }) => {
+  expect(a + b).toBe(expected)
+})
+
+

或在“describe”级别

+
describe.each([
+  ['mobile'], ['tablet'], ['desktop']
+])('checkout flow on %s', (viewport) => {
+  test('displays success page', () => {
+    //
+  })
+})
+
+

describe.each() 文档test.each() 文档,

+

跳过测试

+

不要运行这些测试

+
describe.skip('makePoniesPink'...
+tests.skip('make each pony pink'...
+
+

仅运行以下测试

+
describe.only('makePoniesPink'...
+tests.only('make each pony pink'...
+
+

测试有副作用的模块

+

实例

+
const modulePath = '../module-to-test'
+afterEach(() => {
+  jest.resetModules()
+})
+test('第一次测试', () => {
+  // 准备第一次测试的条件
+  const result = require(modulePath)
+  expect(result).toMatchSnapshot()
+})
+test('第二个文本', () => {
+  // 准备第二次测试的条件
+  const fn = () => require(modulePath)
+  expect(fn).toThrow()
+})
+
+

Node.js 和 Jest 会缓存你需要的模块。 要测试具有副作用的模块,您需要在测试之间重置模块注册表

+

另见

+ + +
+ diff --git a/docs/json.html b/docs/json.html new file mode 100644 index 00000000..c32bead2 --- /dev/null +++ b/docs/json.html @@ -0,0 +1,439 @@ + + + + +JSON 备忘清单 + & Quick Reference + + + + + +

JSON 备忘清单

+

这是理解和编写 JSON 格式配置文件的快速参考备忘单。

+

入门

+

介绍

+

JSON 是一种基于文本的轻量级开放标准,专为人类可读的数据交换而设计。

+
    +
  • JSON 代表 JavaScript 对象表示法
  • +
  • JSON 易于读写。
  • +
  • JSON 是与语言无关的数据交换格式
  • +
  • JSON 文件扩展名为 .json
  • +
  • JSON Internet 媒体类型为 application/json
  • +
+

示例

+
{
+  "name": "Jason",
+  "age": 39,
+  "height": 1.92,
+  "gender": "M",
+  "salary": 70000,
+  "married": true,
+  "children": [
+    {"name": "Tom", "age": 9, "gender":"M"},
+    {"name": "Ava", "age": 7, "gender":"F"}
+  ]
+}
+
+

类型

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
类型描述
Number双精度浮点
String字符系列
Boolean“true”或“false”
Array有序的值序列
Value字符串、数字、布尔值、空值等
Object键/值对的无序集合
nullNull 或 Empty
+

字符串

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
\"双引号 Double quote
\\反斜杠 Backslash
\/正斜杠 Forward slash
\b退格 Backspace
\f换页 Form feed
\n换行 Newline
\r回车 Carriage return
\t标签 Tab
\u后跟四个十六进制数字
+

示例

+
{
+  "url": "https://quickref.me",
+  "msg" : "Hi,\n\"QuickRef.ME\"",
+  "intro": "Share quick reference and cheat sheet for developers."
+}
+
+

无效字符串

+
{ "foo": 'bar' }
+
+

Have to be delimited by double quotes

+

数字

+ + + + + + + + + + + + + + + + + + + + + +
TypeDescription
IntegerDigits 1-9, 0 and positive or negative
FractionFractions like 0.3, 3.9
ExponentExponent like e, e+, e-, E, E+, E
+

示例

+
{
+  "positive" : 12,
+  "negative" : -1,
+  "fraction" : 10.25,
+  "exponent" : 1.0E+2,
+  "zero" : 0
+}
+
+

无效的数字

+
{ "foo": 0xFF }
+
+

在JSON中,只能使用十进制文字

+

对象 Objects

+
{
+  "color": "Purple",
+  "id": "210",
+  "composition": {
+    "R": 70,
+    "G": 39,
+    "B": 89
+  },
+  "empty_object": {}
+}
+
+

用逗号分隔的多个键/值对

+

数组 Arrays

+
[1, 2, 3, 4, 5]
+
+

[ 开始并以 ] 结束

+

对象数组

+
{
+  "children": [
+    { "name": "Jimmy Smith", "age": 15 },
+    { "name": "Sammy Sosa", "age": 12 }
+  ]
+}
+
+

数组对象

+
{
+  "attributes": ["a1", "a2"],
+  "methods": ["getter", "setter"],
+  "empty_array": []
+}
+
+

二维阵列

+
{
+  "my_sequences": [
+    [1, 2, 3],
+    [4, 5, 6],
+    [7, 8, 9, 0],
+    [10, 11]
+  ]
+}
+
+

对象的对象

+
{
+  "Mark McGwire": {
+    "hr": 65,
+    "avg": 0.278
+  },
+  "Sammy Sosa": {
+    "hr": 63,
+    "avg": 0.288
+  }
+}
+
+

嵌套

+
{
+  "Jack": {
+    "id": 1,
+    "name": "Franc",
+    "salary": 25000,
+    "hobby": ["a", "b"],
+    "location": {
+        "country": "A", "city": "A-A"
+    }
+  }
+}
+
+

在 JavaScript 中访问 JSON

+

访问对象

+
let myObject = {
+  "name": "Jason",
+  "last": "Doe",
+  "age": 39,
+  "gender": "M",
+  "salary": 70000,
+  "married": true
+};
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
myObject.name"Jason"
myObject["name"]"Jason"
myObject.age39
myObject.otherundefined
myObject[0]undefined
+

访问嵌套

+
let myObject = {
+    "ref": {
+        "name": 0,
+        "last": 1,
+        "age": 2,
+        "gender": 3,
+        "salary": 4,
+        "married": 5
+    },
+    "jdoe": [
+        "Jason",
+        "Doe",
+        39,
+        "M",
+        70000,
+        true
+    ],
+    "jsmith": [
+        "Tom",
+        "Smith",
+        42,
+        "F",
+        80000,
+        true
+    ]
+};
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
myObject.ref.age2
myObject["ref"]["age"]2
myObject.jdoe["Jason", "Doe", 39 ...]
myObject.jsmith[3]"F"
myObject[1]undefined
+

访问对象数组

+
let myArray = [
+  {
+    "name": "Jason",
+    "last": "Doe",
+    "age": 39,
+    "gender": "M",
+    "salary": 70000,
+    "married": true
+  },
+  {
+    "name": "Tom",
+    "last": "Smith",
+    "age": 42,
+    "gender": "F",
+    "salary": 80000,
+    "married": true
+  },
+  {
+    "name": "Amy",
+    "last": "Burnquist",
+    "age": 29,
+    "gender": "F",
+    "salary": 60000,
+    "married": false
+  }
+];
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
myArray[0]{"name": "Jason", ...}
myArray[1].name"Tom"
myArray[1][2]42
myArray[3]undefined
myArray[3].genderTypeError: Cannot read...
+

访问阵列

+
let myArray = [
+  "Jason",
+  "Doe",
+  39,
+  "M",
+  70000,
+  true
+];
+
+
+ + + + + + + + + + + + + + + + + + + + + +
myArray[1]"Doe"
myArray[5]true
myArray[6]undefined
+

另见

+ + +
+ diff --git a/docs/markdown.html b/docs/markdown.html new file mode 100644 index 00000000..5cf3125a --- /dev/null +++ b/docs/markdown.html @@ -0,0 +1,205 @@ + + + + +Markdown 备忘清单 + & Quick Reference + + + + + +

Markdown 备忘清单

+

这是 Markdown 语法的快速参考备忘单。

+

Markdown 快速参考

+

标题 (atx 风格)

+
# h1
+## h2
+### h3
+#### h4
+##### h5
+###### h6
+
+

标题 (setext 风格)

+
Header 1
+========
+
+
Header 2
+--------
+
+

块引用

+
> 这是一个
+> 块引用
+>
+> > 嵌套
+> > 块引用
+
+

无序列表

+
* Item 1
+* Item 2
+    * item 3a
+    * item 3b
+
+

或者

+
- Item 1
+- Item 2
+
+

或者

+
+ Item 1
++ Item 2
+
+

或者

+
- [ ] Checkbox off
+- [x] Checkbox on
+
+

有序列表

+
1. Item 1
+2. Item 2
+    a. item 3a
+    b. item 3b
+
+

链接

+
[link](http://google.com)
+
+
[link][google]
+[google]: http://google.com
+
+
<http://google.com>
+
+

强调

+
*斜体*
+_斜体_
+
+
**粗体**
+__粗体__
+
+
`内联代码`
+~~删除~~
+
+

水平线

+

连字符

+
---
+
+

星号

+
***
+
+

下划线

+
___
+
+

代码

+
```javascript
+console.log("This is a block code")
+```
+
+
~~~css
+.button { border: none; }
+~~~
+
+
    4 空格缩进做一个代码块
+
+

内联代码

+
`Inline code` 周围有反引号
+
+

表格

+
|     左栏     |     中间栏     |     右栏     |
+|:------------|:-------------:|-------------:|
+| 单元格 1     |   居中         |        $1600 |
+| 单元格 2     |   单元格 3     |          $12 |
+
+

简单的风格

+
    左栏     |     中间栏     |     右栏
+:----------:|:-------------:|:-----------:
+  单元格 1   |   居中         |    $1600
+  单元格 2   |   单元格 3     |     $12
+
+

Markdown 表格生成器:tableconvert.com

+

图片

+
![GitHub Logo](/images/logo.png)
+
+![Alt Text](url)
+
+

带链接的图片

+
[![GitHub Logo](/images/logo.png)](https://github.com/)
+
+[![Alt Text](image_url)](link_url)
+
+

参考风格

+
![alt text][logo]
+
+[logo]: /images/logo.png "Logo Title"
+
+

反斜杠转义

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
字符转义描述
\\\backslash 反斜杠
`\`backtick 反引号
*\*asterisk 星号
_\_underscore 下划线
{}\{}curly braces 花括号
[]\[]square brackets 方括号
()\()parentheses 圆括号
#\#hash mark 哈希标记
+\+plus sign 加号
-\-minus sign (hyphen) 减号(连字符)
.\.dot 点
!\!exclamation mark 感叹号
+ +
+ diff --git a/docs/toml.html b/docs/toml.html new file mode 100644 index 00000000..ee5ef291 --- /dev/null +++ b/docs/toml.html @@ -0,0 +1,185 @@ + + + + +TOML 备忘清单 + & Quick Reference + + + + + +

TOML 备忘清单

+

这是 TOML 格式配置文件语法的快速参考备忘单。

+

入门

+

介绍

+

TOML 是一种最小的配置文件格式,由于明显的语义而易于阅读。

+ +

示例

+
bool = true
+date = 2006-05-27T07:32:00Z
+string = "hello"
+number = 42
+float = 3.14
+scientificNotation = 1e+12
+
+

注释

+
# A single line comment example
+# block level comment example
+# 注释行 1
+# 注释行 2
+# 注释行 3
+
+

整数

+
int1 = +42
+int2 = 0
+int3 = -21
+integerRange = 64
+
+

浮点数

+
float2 = 3.1415
+float4 = 5e+22
+float7 = 6.626e-34
+
+

布尔值

+
bool1 = true
+bool2 = false
+boolMustBeLowercase = true
+
+

时间日期

+
date1 = 1989-05-27T07:32:00Z
+date2 = 1989-05-26T15:32:00-07:00
+date3 = 1989-05-27T07:32:00
+date4 = 1989-05-27
+time1 = 07:32:00
+time2 = 00:32:00.999999
+
+

字符串

+
str1 = "I'm a string."
+str2 = "You can \"quote\" me."
+str3 = "Name\tJos\u00E9\nLoc\tSF."
+
+

See: Strings

+

Table

+
[owner]
+name = "Tom Preston-Werner"
+dob = 1979-05-27T07:32:00-08:00
+
+

See: Tables

+

数组

+
array1 = [1, 2, 3]
+array2 = ["Commas", "are", "delimiter"]
+array3 = [8001, 8001, 8002]
+
+

友好数组

+
array1 = [ "Don't mix", "different", "types" ]
+array2 = [ [ 1.2, 2.4 ], ["all", 'strings', """are the same""", '''type'''] ]
+array3 = [
+  "Whitespace", "is", 
+  "ignored"
+]
+
+

TOML 字符串

+

多行字符串

+
multiLineString = """
+Multi-line basic strings are surrounded
+by three quotation marks on each side
+and allow newlines. 
+"""
+
+

文字字符串

+
path = 'C:\Users\nodejs\templates'
+path2 = '\\User\admin$\system32'
+quoted = 'Tom "Dubs" Preston-Werner'
+regex = '<\i\c*\s*>'
+
+

用单引号括起来。不允许转义。

+

多行文字字符串

+
re = '''\d{2} apps is t[wo]o many'''
+lines = '''
+The first newline is
+trimmed in raw strings.
+All other whitespace
+is preserved.
+'''
+
+

TOML Tables

+

基本的

+
[name]
+foo = 1
+bar = 2
+
+

foobar 是名为name 的表中的键

+

嵌套

+
[table1]
+	foo = "bar"
+[table1.nested_table]
+	baz = "bat"
+
+

类数组

+
[[comments]]
+author = "Nate"
+text = "Great Article!"
+[[comments]]
+author = "Anonymous"
+text = "Love it!"
+
+

↓ 等效的 JSON

+
{
+	"comments" : [
+		{
+			"author" : "Nate",
+			"text" : "Great Article!"
+		},
+		{
+			"author" : "Anonymous",
+			"text" : "Love It!"
+		}
+	]
+}
+
+

点分隔

+
[dog."tater.man"]
+type = "pug"
+
+

↓ 等效的 JSON

+
{
+  "dog": {
+    "tater.man": {
+      "type": "pug"
+    }
+  }
+}
+
+

多嵌套

+
[foo.bar.baz]
+bat = "hi"
+
+

↓ 等效的 JSON

+
{
+	"foo" : {
+		"bar" : {
+			"baz" : {
+				"bat" : "hi"
+			}
+		}
+	}
+}
+
+

忽略空格

+
[a.b.c]          # this is best practice
+[ d.e.f ]        # same as [d.e.f]
+[ g .  h  .i ]   # same as [g.h.i]
+[ j . "ʞ" .'l' ] # same as [j."ʞ".'l']
+
+

Inline Table

+
name = { first = "Tom", last = "Preston-Werner" }
+point = { x = 1, y = 2 }
+animal = { type.name = "pug" }
+
+ +
+ diff --git a/docs/typescript.html b/docs/typescript.html new file mode 100644 index 00000000..5734cc34 --- /dev/null +++ b/docs/typescript.html @@ -0,0 +1,904 @@ + + + + +TypeScript 备忘清单 + & Quick Reference + + + + + +

TypeScript 备忘清单

+

包含最重要基础、泛型、方法、class 等 TypeScript 强类型编程语言语法的快速参考备忘单。初学者的完整快速参考。

+

入门 Interface

+

介绍

+

TypeScript 是具有类型语法的 JavaScript。Interface 是为了匹配它们的运行时行为而构建的。

+ +

内置类型基元

+
boolean, string, number,
+undefined, null,
+any, unknown, never,
+void, bigint, symbol
+
+

常见的内置 JS 对象

+
Date, Error,
+Array, Map, Set,
+Regexp, Promise
+
+

内置

+

类型字面量

+

Object:

+
{ field: string }
+
+

Function:

+
(arg: number) => string
+
+

Arrays:

+
string[] or Array<string>
+
+

Tuple:

+
[string, number]
+
+

避免

+
Object, String, Number, Boolean
+
+

通用语法

+
/** 可选择从现有接口或类型(Response, HTTPAble)中获取属性 */
+interface JSONResponse extends Response, HTTPAble {
+  version: number;
+  // 👇  附加在编辑器中显示的 JSDoc 注释
+  /** In bytes */
+  payloadSize: number;
+  // 👇  此属性可能不在对象上
+  outOfStock?: boolean;
+  // 👇  这是描述作为函数的属性的两种方法
+  update: (retryTimes: number) => void;
+  update(retryTimes: number): void;
+  // 👇  你可以通过 () 调用这个对象 -(JS中的函数是可以调用的对象)
+  (): JSONResponse
+  // 👇  您可以在此 Interface 描述的对象上使用 new
+  new(s: string): JSONResponse;
+  // 👇  任何未描述的属性都假定存在,并且所有属性必须是数字
+  [key: string]: number;
+  // 👇  告诉 TypeScript 一个属性不能被改变
+  readonly body: string;
+}
+
+

泛型

+

声明一个可以在你的 Interface 中改变的类型

+
interface APICall<Response> {
+  data: Response
+}
+
+

用法

+
const api: APICall<ArtworkCall> = ...
+
+api.data  // Artwork
+
+

您可以通过 extends 关键字限制泛型参数接受的类型。

+
interface APICall<Response extends { status: number }> {
+  data: Response
+}
+
+const api: APICall<ArtworkCall> = ...
+
+api.data.status
+
+

重载

+
interface Expect {
+  (matcher: boolean): string
+  (matcher: string): boolean;
+}
+
+

一个可调用 Interface 可以对不同的参数集有多个定义。

+

类一致性

+
interface Syncable {
+  sync(): void
+}
+class Account implements Syncable { ... }
+
+

您可以通过实现确保类 class 符合 Interface。

+

Get & Set

+

对象可以有自定义的 gettersetter

+
interface Ruler {
+  get size(): number
+  set size(value: number | string);
+}
+
+

用法

+
const r: Ruler = ...
+r.size = 12
+r.size = "36"
+
+

通过合并扩展

+
interface APICall {
+  data: Response
+}
+
+interface APICall {
+  error?: Error
+}
+
+

Interface 被合并,多个声明将向类型定义添加新字段。

+

Type

+

Type vs Interface

+
    +
  • Interface 只能描述对象形状
  • +
  • Interface 可以通过多次声明来扩展
  • +
  • 在性能关键 Type 中,Interface 比较检查可以更快。
  • +
+

把类型想象成变量

+

就像您如何在不同范围内创建具有相同名称的变量一样,type 具有相似的语义。

+

使用实用程序类型构建

+

TypeScript 包含许多全局类型,它们将帮助您在类型系统中完成常见任务。检查他们的网站。

+

原始类型

+
type SanitizedInput = string;
+type MissingNo = 404;
+
+

主要用于文档

+

对象字面类型

+
type Location = {
+  x: number;
+  y: number;
+};
+
+

联合类型

+
type Size = "small" | "medium" | "large"
+
+

描述许多选项中的一个类型,例如已知字符串的列表。

+

交叉口类型

+
type Location = { x: number }
+              & { y: number }
+// { x: number, y: number }
+
+

一种合并/扩展类型的方法

+

从值类型

+
const data = { ... }
+type Data = typeof data
+
+

通过 typeof 运算符重用来自现有 JavaScript 运行时值的类型。

+

从函数返回类型

+
const createFixtures = () => { ... }
+type Fixtures = ReturnType<typeof createFixtures>
+function test(fixture: Fixtures) {}
+
+

将函数的返回值重新用作类型。

+

从模块类型

+
const data: import("./data").data
+
+

这些功能非常适合构建库、描述现有的 JavaScript 代码,您可能会发现在大多数 TypeScript 应用程序中很少使用它们。

+

对象字面量语法

+
type JSONResponse = {
+  version: number;                        // 字段
+  /** In bytes */                         // 附加文档
+  payloadSize: number;
+  outOfStock?: boolean;                   // 可选的
+  update: (retryTimes: number) => void;   // 箭头函数字段
+  update(retryTimes: number): void;       // 函数
+  (): JSONResponse                        // 类型是可调用的
+  [key: string]: number;                  // 接受任何索引
+  new (s: string): JSONResponse;          // new 对象
+  readonly body: string;                  // 只读属性
+}
+
+

用于节省空间的 Terser,请参阅 Interface 备忘清单了解更多信息,除了“static”匹配之外的所有内容。

+

映射类型

+
type Artist = {
+  name: string, bio: string
+}
+
+type Subscriber<Type> = {
+  [Property in keyof Type]: 
+      (newValue: Type[Property]) => void
+}
+type ArtistSub = Subscriber<Artist>
+// { name: (nv: string) => 
+//    void, bio: (nv: string) => void }
+
+

类似于类型系统的映射语句,允许输入类型更改新类型的结构。

+

模板联合类型

+
type SupportedLangs =  "en" | "pt" | "zh";
+type FooterLocaleIDs = "header" | "footer";
+type AllLocaleIDs = `${SupportedLangs}_${FooterLocaleIDs}_id`;
+
+// "en_header_id" | "en_footer_id"
+//         | "pt_header_id" | "pt_footer_id"
+//         | "zh_header_id" | "zh_footer_id"
+
+

条件类型

+
type HasFourLegs<Animal> = Animal extends { legs: 4 } ? Animal : never
+type Animals = Bird | Dog | Ant | Wolf;
+type FourLegs = HasFourLegs<Animals>
+// Dog | Wolf
+
+

在类型系统中充当“if 语句”。 通过泛型创建,然后通常用于减少类型联合中的选项数量。

+

控制流动分析

+

If 声明

+

typeof(用于原语)

+
const input = getUserInput()
+input // string | number
+
+if (typeof input === 'string') {
+ input // string
+}
+
+

对象中的“property”(对于对象)

+
const input = getUserInput()
+input  // string | { error: ... }
+
+if ('error' in input) {
+  input // { error: ... }
+}
+
+

instanceof(用于类)

+
const input = getUserInput()
+  input // number | number[]
+
+if (input instanceof Array) {
+  input // number[]
+}
+
+

类型保护功能(适用于任何东西)

+
const input = getUserInput()
+   input // number | number[]
+
+if (Array.isArray(input)) {
+  input // number[]
+}
+
+

任务

+
const data1 = {
+  name: "Zagreus"
+}
+// typeof data1 = {
+//   name: string
+// }
+
+

使用 as const 缩小类型

+
const data2 = {
+  name: "Zagreus"
+} as const
+// typeof data1 = {
+//   name: 'Zagreus'
+// }
+
+

跟踪相关变量

+
const response = getResponse()
+const isSuccessResponse = 
+    res instanceof SuccessResponse
+
+if (isSuccessResponse) {
+  res.data // SuccessResponse
+}
+
+

重新分配更新类型

+
let data: string | number = ...
+data // string | number
+data = "Hello"
+data // string
+
+

关键点

+

CFA 几乎总是采用联合,并根据代码中的逻辑减少联合内的类型数量。

+

大多数时候 CFA 在自然 JavaScript 布尔逻辑中工作,但是有一些方法可以定义您自己的函数,这些函数会影响 TypeScript 如何缩小类型。

+

表达式

+
const input = getUserInput()
+input // string | number
+const inputLength =
+  (typeof input === "string" && input.length)
+  || input
+   // input: string
+
+

在进行布尔运算时,缩窄也发生在与代码相同的行上

+

可识别联合

+
type Responses =
+  | { status: 200, data: any }
+  | { status: 301, to: string }
+  | { status: 400, error: Error }
+
+

用法

+
const response = getResponse()
+response // Responses
+switch(response.status) {
+  case 200: return response.data
+  case 301: return redirect(response.to)
+  case 400: return response.error
+}
+
+

断言函数

+

描述影响当前范围的 CFA 更改的函数,因为它抛出而不是返回 false。

+
function assertResponse(obj: any):
+    asserts obj is SuccessResponse {
+  if (!(obj instanceof SuccessResponse)) {
+    throw new Error('Not a success!')
+  }
+}
+
+

用法

+
const res = getResponse():
+res // SuccessResponse | ErrorResponse
+
+// 断言函数改变当前作用域或抛出
+assertResponse(res)
+
+res // SuccessResponse
+
+

Class

+

创建类实例

+
class ABC { ... }
+const abc = new ABC()
+
+

新 ABC 的参数来自构造函数。

+

private x 与 #private

+

前缀 private 是一个仅类型的添加,在运行时没有任何影响。 在以下情况下,类之外的代码可以进入项目:

+
class Bag {
+  private item: any
+}
+
+

Vs #private 是运行时私有的,并且在 JavaScript 引擎内部强制执行,它只能在类内部访问:

+
class Bag { #item: any }
+
+

Class 上的 “this”

+

函数内部‘this’的值取决于函数的调用方式。 不能保证始终是您可能在其他语言中使用的类实例。

+

您可以使用“此参数”、使用绑定功能或箭头功能来解决问题。

+

类型和值

+

一个类既可以用作类型也可以用作值。

+
const a:Bag = new Bag()
+
+

所以,小心不要这样做:

+
class C implements Bag {}
+
+

通用语法

+
// 确保类符合一组接口或类型  ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈▶┈┈╮
+// 子类这个类 ┈┈┈┈┈┈┈┈↘                 ┈┈┈┈┈┈┈┈┈┈┈┈┈┴┈┈┈┈┈┈┈
+class User extends Account implements Updatable, Serializable {
+  id: string;                     // 一个字段
+  displayName?: boolean;          // 可选字段
+  name!: string;                  // '相信我,它在哪里'字段
+  #attributes: Map<any, any>;     // 私人字段
+  roles = ["user"];               // 具有默认值的字段
+  readonly createdAt = new Date() // 具有默认值的只读字段
+  // 👇 代码调用“new”
+  constructor(id: string, email: string) {
+    super(id);
+    // 👇 在 `strict: true` 中,会根据字段检查此代码以确保其设置正确
+    this.email = email;
+    // ....
+  };
+  // 👇 描述类方法(和箭头函数字段)的方式
+  setName(name: string) { this.name = name }
+  verifyName = (name: string) => { /* ... */ }
+
+  // 👇 具有 2 个重载定义的函数
+  sync(): Promise<{ ... }>
+  sync(cb: ((result: string) => void)): void
+  sync(cb?: ((result: string) => void)): void | Promise<{ ... }> {}
+  // 👇 Getters 和 setters
+  get accountID() { }
+  set accountID(value: string) { }
+  // 👇 私有访问只是对这个类,受保护的允许子类。 仅用于类型检查,public 是默认值。
+  private makeRequest() { ... }
+  protected handleRequest() { ... }
+  // 👇 静态字段/方法
+  static #userCount = 0;
+  static registerUser(user: User) { ... }
+  // 👇 用于设置静态变量的静态块。 ‘this’指的是静态类
+  static { this.#userCount = -1 }
+}
+
+

泛型

+

声明一个可以在你的类方法中改变的类型。

+
class Box<Type> {
+  contents: Type
+  constructor(value: Type) {
+    this.contents = value;
+  }
+}
+const stringBox = new Box("a package")
+
+

这些功能是 TypeScript 特定的语言扩展,可能永远无法使用当前语法进入 JavaScript。

+

参数属性

+
class Location {
+  constructor(public x: number, public y: number) {}
+}
+const loc = new Location(20, 40);
+
+loc.x // 20
+loc.y // 40
+
+

TypeScript 特定于类的扩展,可自动将实例字段设置为输入参数。

+

抽象类

+
abstract class Animal {
+  abstract getName(): string;
+  printName() {
+    console.log("Hello, " + this.getName());
+  }
+}
+class Dog extends Animal { getName(): { ... } }
+
+

一个类可以被声明为不可实现,但可以在类型系统中被子类化。 class 成员也可以。

+

装饰器和属性

+
import { Syncable, triggersSync, preferCache, required } from "mylib"
+
+@Syncable
+class User {
+  @triggersSync()
+  save() { ... }
+  @preferCache(false)
+  get displayName() { ... }
+  update(@required info: Partial<User>) { ... }
+}
+
+

您可以在类、类方法、访问器、属性和方法参数上使用装饰器。

+

索引签名

+
class MyClass {
+  // 最好将索引数据存储在另一个地方
+  // 而不是类实例本身。
+  [s: string]:
+    boolean | ((s: string) => boolean);
+
+  check(s: string) {
+    return this[s] as boolean;
+  }
+}
+
+

类可以声明索引签名,与其他对象类型的索引签名相同。

+

实用程序类型

+

Awaited<Type>

+
type A = Awaited<Promise<string>>;
+// type A = string
+
+type B = Awaited<Promise<Promise<number>>>;
+// type B = number
+
+type C = Awaited<boolean|Promise<number>>;
+// type C = number | boolean
+
+

这种类型旨在模拟异步函数中的 await 或 Promises 上的 .then() 方法等操作 - 特别是它们递归解包 Promises 的方式。

+

Required<Type>

+
interface Props {
+  a?: number;
+  b?: string;
+}
+
+const obj: Props = { a: 5 }; 
+const obj2: Required<Props> = { a: 5 };
+// ❌ 类型“{ a: number;”中缺少属性“b” }' 
+// 但在 'Required<Props>' 类型中是必需的。
+
+

使 Type 中的所有属性成为必需

+

Readonly<Type>

+
interface Todo {
+  title: string;
+}
+const todo: Readonly<Todo> = {
+  title: "Delete inactive users",
+};
+todo.title = "Hello";
+// ❌ 无法分配给“title”,因为它是只读属性。
+
+function freeze<Type>(obj: Type)
+            : Readonly<Type>;
+
+

将 Type 中的所有属性设为只读

+

Partial<Type>

+
interface Todo {
+  title: string;
+  description: string;
+}
+function updateTodo(
+  todo: Todo,
+  fieldsToUpdate: Partial<Todo>
+) {
+  return { ...todo, ...fieldsToUpdate };
+}
+const todo1 = {
+  title: "organize desk",
+  description: "clear clutter",
+};
+const todo2 = updateTodo(todo1, {
+  description: "throw out trash",
+});
+
+

Type 中的所有属性设为可选

+

Record<Keys, Type>

+
interface CatInfo {
+  age: number;
+  breed: string;
+}
+
+type CatName = "miffy" | "boris";
+const cats: Record<CatName, CatInfo> = {
+  miffy: {age:10, breed: "Persian" },
+  boris: {age:5, breed: "Maine Coon" },
+};
+
+cats.boris; 
+// 👉 const cats: Record<CatName, CatInfo>
+
+

构造一个具有一组 Keys 类型的属性 Type 的类型

+

Pick<Type, Keys>

+
interface Todo {
+  name: string;
+  description: string;
+  completed: boolean;
+}
+type TodoPreview = Pick<
+  Todo, "name" | "load"
+>;
+const todo: TodoPreview = {
+  name: "Clean room",
+  load: false,
+};
+
+todo;
+ // 👉 const todo: TodoPreview
+
+

从 Type 中选择一组其键在并集 Keys 中的属性

+

Exclude<UnionType, ExcludedMembers>

+
type T0 = Exclude<"a" | "b" | "c", "a">;
+// 👉 type T0 = "b" | "c"
+
+type T1 = Exclude<"a"|"b"|"c", "a" | "b">;
+// 👉 type T1 = "c"
+
+type T2 = Exclude<string | number |
+    (() => void), Function>;
+// 👉 type T2 = string | number
+
+

UnionType排除那些可分配给 ExcludedMembers 的类型

+

Extract<Type, Union>

+
type T0 = Extract<
+  "a" | "b" | "c", "a" | "f"
+>;
+// type T0 = "a"
+type T1 = Extract<
+  string | number | (() => void),
+  Function
+>;
+// type T1 = () => void
+
+

通过从 Type 中提取所有可分配给 Union 的联合成员来构造一个类型。

+

NonNullable<Type>

+
type T0 = NonNullable<
+  string | number | undefined
+>;
+// type T0 = string | number
+
+type T1 = NonNullable<
+  string[] | null | undefined
+>;
+// type T1 = string[]
+
+

通过从 Type 中排除 null 和 undefined 来构造一个类型。

+

Omit<Type, Keys>

+
interface Todo {
+  name: string;
+  completed: boolean;
+  createdAt: number;
+}
+ 
+type TodoPreview = Omit<Todo, "name">;
+
+const todo: TodoPreview = {
+  completed: false,
+  createdAt: 1615544252770,
+};
+ 
+todo;
+ // 👉 const todo: TodoPreview
+
+

构造一个具有 Type 属性的类型,但类型 Keys 中的属性除外

+

Parameters<Type>

+
declare function f1(
+  arg: { a: number; b: string }
+): void;
+
+type T0 = Parameters<() => string>;
+// type T0 = []
+type T1 = Parameters<(s: string) => void>;
+// type T1 = [s: string]
+type T2 = Parameters<<T>(arg: T) => T>;
+// type T2 = [arg: unknown]
+type T3 = Parameters<typeof f1>;
+// type T3 = [arg: {
+//     a: number;
+//     b: string;
+// }]
+type T4 = Parameters<any>;
+// type T4 = unknown[]
+type T5 = Parameters<never>;
+// type T5 = never
+
+

从函数类型 Type 的参数中使用的类型构造元组类型。

+

ConstructorParameters<Type>

+
type T0 = ConstructorParameters<
+  ErrorConstructor
+>;
+// type T0 = [message?: string]
+type T1 = ConstructorParameters<
+  FunctionConstructor
+>;
+// type T1 = string[]
+type T2 = ConstructorParameters<
+  RegExpConstructor
+>;
+// type T2 = [
+//    pattern: string | RegExp,
+//    flags?: string
+// ]
+type T3 = ConstructorParameters<any>;
+// type T3 = unknown[]
+
+

从构造函数类型的类型构造元组或数组类型。它产生一个包含所有参数类型的元组类型(如果 Type 不是函数,则类型 never )。

+

内在字符串操作类型

+

Uppercase<StringType>

+
type Greeting = "Hello, world"
+type ShoutyGreeting = Uppercase<Greeting>
+// type ShoutyGreeting = "HELLO, WORLD"
+
+type ASCIICacheKey<Str extends string> = `ID-${Uppercase<Str>}`
+type MainID = ASCIICacheKey<"my_app">
+// type MainID = "ID-MY_APP"
+
+

将字符串中的每个字符转换为大写版本。

+

Lowercase<StringType>

+
type Greeting = "Hello, world"
+type QuietGreeting = Lowercase<Greeting>
+// type QuietGreeting = "hello, world"
+
+type ASCIICacheKey<Str extends string> = `id-${Lowercase<Str>}`
+type MainID = ASCIICacheKey<"MY_APP">
+// type MainID = "id-my_app"
+
+

将字符串中的每个字符转换为等效的小写字母

+

Capitalize<StringType>

+
type LowercaseGreeting = "hello, world";
+type Greeting = Capitalize<LowercaseGreeting>;
+// type Greeting = "Hello, world"
+
+

将字符串中的第一个字符转换为等效的大写字母

+

Uncapitalize<StringType>

+
type UppercaseGreeting = "HELLO WORLD";
+type UncomfortableGreeting = Uncapitalize<UppercaseGreeting>;
+// type UncomfortableGreeting = "hELLO WORLD"
+
+

将字符串中的第一个字符转换为等效的小写字母

+

ReturnType<Type>

+
declare function f1(): {
+  a: number; b: string
+};
+
+type T0 = ReturnType<() => string>;
+// type T0 = string
+
+type T1 = ReturnType<(s: string) => void>;
+// type T1 = void
+
+type T2 = ReturnType<<T>() => T>;
+// type T2 = unknown
+
+type T3 = ReturnType<<
+  T extends U, U extends number[]
+>() => T>;
+// type T3 = number[]
+
+type T4 = ReturnType<typeof f1>;
+// type T4 = {
+//     a: number;
+//     b: string;
+// }
+
+type T5 = ReturnType<any>;
+// type T5 = any
+
+type T6 = ReturnType<never>;
+// type T6 = never
+
+

构造一个由函数 Type 的返回类型组成的类型。

+

ThisType<Type>

+
type ObjectDescriptor<D, M> = {
+  data?: D;
+  // 方法中“this”的类型是 D & M
+  methods?: M & ThisType<D & M>;
+};
+ 
+function makeObject<D, M>(
+  desc: ObjectDescriptor<D, M>
+): D & M {
+  let data: object = desc.data || {};
+  let methods: object = desc.methods || {};
+  return { ...data, ...methods } as D & M;
+}
+ 
+let obj = makeObject({
+  data: { x: 0, y: 0 },
+  methods: {
+    moveBy(dx: number, dy: number) {
+      this.x += dx; // Strongly typed this
+      this.y += dy; // Strongly typed this
+    },
+  },
+});
+ 
+obj.x = 10;
+obj.y = 20;
+obj.moveBy(5, 5);
+
+

此实用程序不返回转换后的类型。 相反,它用作上下文 this 类型的标记。 请注意,必须启用 noImplicitThis 标志才能使用此实用程序。

+

InstanceType<Type>

+
class C {
+  x = 0;
+  y = 0;
+}
+type T0 = InstanceType<typeof C>;
+// type T0 = C
+type T1 = InstanceType<any>;
+// type T1 = any
+type T2 = InstanceType<never>;
+// type T2 = never
+
+

构造一个由 Type 中构造函数的实例类型组成的类型。

+

ThisParameterType<Type>

+
function toHex(this: Number) {
+  return this.toString(16);
+}
+ 
+function numberToString(
+  n: ThisParameterType<typeof toHex>
+) {
+  return toHex.apply(n);
+}
+
+

提取函数类型的 this 参数的类型,如果函数类型没有 this 参数,则为未知。

+

OmitThisParameter<Type>

+
function toHex(this: Number) {
+  return this.toString(16);
+}
+const fiveToHex
+  : OmitThisParameter<typeof toHex>
+  = toHex.bind(5);
+
+console.log(fiveToHex());
+
+

从 Type 中移除 this 参数。 如果 Type 没有显式声明此参数,则结果只是 Type。 否则,从 Type 创建一个不带此参数的新函数类型。 泛型被删除,只有最后一个重载签名被传播到新的函数类型中。

+

JSX

+

JSX 介绍

+

JSX 规范是对 ECMAScript 的类似 XML 的语法扩展。

+
    +
  • 使用 .tsx 扩展名命名您的文件
  • +
  • 启用 jsx 选项
  • +
  • 不允许在 .tsx 文件中使用尖括号类型断言。
  • +
  • JSX 规范
  • +
+

as 运算符

+
const foo = <foo>bar;
+// 不允许在 .tsx 👆 文件中使用尖括号类型断言。
+
+const foo = bar as foo;
+
+

as 运算符在 .ts.tsx 文件中都可用,并且在行为上与尖括号类型断言样式相同。

+

基于值的元素

+
import MyComponent from "./myComponent";
+
+<MyComponent />; // ok
+<SomeOtherComponent />; // ❌ error
+
+

基于值的元素只是由范围内的标识符查找。

+

内在的元素

+
declare namespace JSX {
+  interface IntrinsicElements {
+    foo: any;
+  }
+}
+<foo />; // ok
+<bar />; // error
+
+

<bar /> 没有在 JSX.IntrinsicElements 上指定。

+
declare namespace JSX {
+  interface IntrinsicElements {
+    [elemName: string]: any;
+  }
+}
+
+

函数组件

+
interface FooProp {
+  name: string;
+  X: number;
+  Y: number;
+}
+declare function AnotherComponent(prop: { name: string });
+function ComponentFoo(prop: FooProp) {
+  return <AnotherComponent name={prop.name} />;
+}
+
+const Button = (prop: { value: string }, context: { color: string }) => (
+  <button />
+);
+
+

该组件被定义为一个 JavaScript 函数,其第一个参数是一个 props 对象。 TS 强制它的返回类型必须可分配给 JSX.Element。

+

函数组件重载

+
interface CeProps {
+  children: JSX.Element[] | JSX.Element;
+}
+ 
+interface HomeProps extends CeProps {
+  home: JSX.Element;
+}
+ 
+interface SideProps extends CeProps {
+  side: JSX.Element | string;
+}
+ 
+function Dog(prop: HomeProps): JSX.Element;
+function Dog(prop: SideProps): JSX.Element;
+function Dog(prop: CeProps): JSX.Element {
+  // ...
+}
+
+

函数子组件

+
interface MenuProps extends React.LiHTMLAttributes<HTMLUListElement> { ... }
+const InternalMenu = (props: MenuProps, ref?: React.ForwardedRef<HTMLUListElement>) => (
+  <ul {...props} ref={ref} />
+);
+type MenuComponent = React.FC<React.PropsWithRef<MenuProps>> & {
+  Item: typeof MenuItem;    // MenuItem 函数组件
+  SubMenu: typeof SubMenu;  // SubMenu 函数组件
+};
+const Menu: MenuComponent = React.forwardRef<HTMLUListElement>(
+  InternalMenu
+) as unknown as MenuComponent;
+
+Menu.Item = MenuItem;
+Menu.SubMenu = SubMenu;
+
+<Menu.Item />     // ok
+<Menu.SubMenu />  // ok
+
+

类组件

+
class MyComponent {
+  render() {}
+}
+// 使用构造签名
+const myComponent = new MyComponent();
+// element class type => MyComponent
+// element instance type => { render: () => void }
+
+function MyFactoryFunction() {
+  return {
+    render: () => {},
+  };
+}
+// 使用调用签名
+const myComponent = MyFactoryFunction();
+// element class type => MyFactoryFunction
+// element instance type => { render: () => void }
+
+

元素实例类型很有趣,因为它必须可以分配给JSX。ElementClass,否则将导致错误。默认情况下,JSX。ElementClass 是 {},但可以对其进行扩展,以将JSX的使用限制为仅限于符合适当接口的类型。

+
declare namespace JSX {
+  interface ElementClass {
+    render: any;
+  }
+}
+class MyComponent {
+  render() {}
+}
+function MyFactoryFunction() {
+  return { render: () => {} };
+}
+<MyComponent />; // ok
+<MyFactoryFunction />; // ok
+
+class NotAValidComponent {}
+function NotAValidFactoryFunction() {
+  return {};
+}
+<NotAValidComponent />; // ❌ error
+<NotAValidFactoryFunction />; // ❌ error
+
+ +
+ diff --git a/docs/vscode.html b/docs/vscode.html new file mode 100644 index 00000000..526c17b0 --- /dev/null +++ b/docs/vscode.html @@ -0,0 +1,611 @@ + + + + +VSCode 备忘清单 + & Quick Reference + + + + + +

VSCode 备忘清单

+

这个 VSCode (Visual Studio Code) 快速参考备忘单显示了它的键盘快捷键和命令。

+

Windows

+

一般的

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
--
Ctrl Shift P / F1显示命令面板
Ctrl P快速打开,转到文件
Ctrl Shift N新窗户
Ctrl Shift W关闭窗口
Ctrl ,用户设置
Ctrl K Ctrl S键盘快捷键
+

基本编辑

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
--
Ctrl X剪切行
Ctrl C复制行
Alt / 向上/向下移动行
Shift Alt / 向上/向下复制行
Ctrl Shift K删除行
Ctrl Enter在下面插入行
Ctrl Shift Enter在上面插入行
Ctrl Shift \跳转到匹配的括号
Ctrl ] / [缩进/突出行
Home / End转到行首/行尾
Ctrl Home转到文件开头
Ctrl End转到文件末尾
Ctrl / 向上/向下滚动行
Alt PgUp / PgDn向上/向下滚动页面
Ctrl Shift [折叠(折叠)区域
Ctrl Shift ]展开(展开)区域
Ctrl K Ctrl [折叠(折叠)所有子区域
Ctrl K Ctrl ]展开(展开)所有子区域
Ctrl K Ctrl 0折叠(折叠)所有区域
Ctrl K Ctrl J展开(展开)所有区域
Ctrl K Ctrl C添加行注释
Ctrl K Ctrl U删除行注释
Ctrl /切换行注释
Shift Alt A切换块评论
Alt Z切换自动换行
+

导航

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
--
Ctrl T显示所有符号
Ctrl G去线
Ctrl P转到文件
Ctrl Shift O转到符号
Ctrl Shift M显示问题面板
F8转到下一个错误
Shift F8转到上一个错误
Ctrl Shift Tab浏览编辑组历史
Alt / 后退/前进
Ctrl M切换 Tab 移动焦点
+

搜索和替换

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
--
Ctrl F寻找
Ctrl H代替
F3 / Shift F3查找下一个/上一个
Alt Enter选择所有出现的查找匹配项
Ctrl D将选择添加到下一个查找匹配项
Ctrl K Ctrl D将最后一个选择移动到下一个查找匹配项
Alt C / R / W切换区分大小写/正则表达式/整个单词
+

多光标和选择

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
--
Alt Click插入光标
Ctrl Alt / 在上方/下方插入光标
Ctrl U撤消上一次光标操作
Shift Alt I在选定的每一行的末尾插入光标
Ctrl I选择当前行
Ctrl Shift L选择当前选择的所有匹配项
Ctrl F2选择当前单词的所有出现
Shift Alt 展开选择
Shift Alt 收缩选择
Shift Alt <Drag>列(框)选择
Ctrl Shift Alt <Arrow>列(框)选择
Ctrl Shift Alt PgUp / PgDn列(框)选择页上/下
+

丰富的语言编辑

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
--
Ctrl <Space> Ctrl I触发建议
Ctrl Shift <Space>触发参数提示
Shift Alt F格式化文档
Ctrl K Ctrl F格式选择
F12转到定义
Alt F12窥视定义
Ctrl K F12打开定义到一边
Ctrl .快速解决
Shift F12显示参考
F2重命名符号
Ctrl K Ctrl X修剪尾随空格
Ctrl K M更改文件语言
+

编辑管理

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
--
Ctrl F4 Ctrl W关闭编辑器
Ctrl K F关闭文件夹
Ctrl \拆分编辑器
Ctrl 1 / 2 / 3专注于第一、第二或第三编辑组
Ctrl K Ctrl / 专注于上一个/下一个编辑组
Ctrl Shift PgUp / PgDn向左/向右移动编辑器
Ctrl K / 移动活动编辑器组
+

文件管理

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
--
Ctrl N新建文件
Ctrl O打开文件
Ctrl S保存
Ctrl Shift S另存为
Ctrl K S保存所有
Ctrl F4关闭
Ctrl K Ctrl W关闭松油
Ctrl Shift T重新打开关闭的编辑器
Ctrl K Enter保持预览模式编辑器打开
Ctrl TabOpen next
Ctrl Shift TabOpen previous
Ctrl K P复制活动文件的路径
Ctrl K R在资源管理器中显示活动文件
Ctrl K O在新窗口/实例中显示活动文件
+

展示

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
--
F11切换全屏
Shift Alt 0切换编辑器布局(水平/垂直)
Ctrl = / -放大/缩小
Ctrl B切换侧边栏可见性
Ctrl Shift E显示资源管理器/切换焦点
Ctrl Shift F显示搜索
Ctrl Shift G显示源代码管理
Ctrl Shift D显示调试
Ctrl Shift X显示扩展
Ctrl Shift H在文件中替换
Ctrl Shift J切换搜索详细信息
Ctrl Shift U显示输出面板
Ctrl Shift V打开 Markdown 预览
Ctrl K V打开 Markdown 预览到一边
Ctrl K ZZen 模式(Esc Esc 退出)
+

调试

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
--
F9切换断点
F5开始/继续
Shift F5停止
Shift F11 / F11进/出
F10跨过去
Ctrl K Ctrl I显示悬停
Ctrl `显示综合终端
Ctrl Shift `创建一个新终端
Ctrl C复制选择
Ctrl V粘贴到活动终端
Ctrl / 向上/向下滚动
Shift PgUp / PgDn向上/向下滚动页面
Ctrl Home / End滚动到顶部/底部
+ +
+ diff --git a/index.html b/index.html new file mode 100644 index 00000000..5f7c090c --- /dev/null +++ b/index.html @@ -0,0 +1,37 @@ + + + + +Quick Reference + & Quick Reference + + + + + +

Quick Reference

+

为开发人员分享快速参考备忘单(主要是方便自己),在看到 Reference 快速参考备忘单,感觉非常简单,造轮子使命感突然来了,造个中文版本的,为了方便自己的技术栈查阅,立马撸起来 :)。

+

如果您发现此处的备忘单不合适,您可以通过提交 PR 来修复它或提供更好的备忘清单,只针对【中文】用户。以下是开源天使提供的一些备忘清单和快速参考 :)。

+

编程

工具包

+

+ VSCode + Jest +

+

Linux 命令

+

+ Cron + Git +

+

License

+

MIT © Kenny Wong

+ +
+ diff --git a/style/style.css b/style/style.css new file mode 100644 index 00000000..0b30cbfd --- /dev/null +++ b/style/style.css @@ -0,0 +1,612 @@ +body { + -webkit-text-size-adjust: 100%; + tab-size: 4; + margin: 0; + line-height: inherit; + font-family: ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; +} + +body { + background-color: rgb(15 23 42/1); + color: rgb(203 213 225/1); +} + +*, ::before, ::after { + box-sizing: border-box; + border-width: 0; + border-style: solid; + border-color: #e5e7eb; +} + +blockquote, dl, dd, h1, h2, h3, h4, h5, h6, hr, figure, p, pre { + margin: 0; +} + +.max-container a, .max-container a:visited { + color: rgb(2 132 199/1); + text-decoration: none; + background-image: linear-gradient(transparent,transparent 6px,#34495e 6px,#34495e); + background-position: bottom; + background-size: 100% 6px; + background-repeat: repeat-x; +} + +.max-container a:hover, .max-container a:visited:hover{ + text-decoration-line: underline; + text-decoration-color: #10b981; + text-decoration-thickness: 2px; + text-underline-offset: 4px; +} + +.max-container { + max-width: 1320px; + margin-left: auto; + margin-right: auto; + padding: 0.75rem; +} + +body.home .h1warp-body, body.home .h1warp .warp-body { + max-width: 940px; + margin-left: auto; + margin-right: auto; + padding: 0.75rem; +} +body.home .h2warp > h2 { + display: inline-block; + padding-right: 0.5rem; +} + +body.home .h2warp > h2::after { + content: ' '; + display: block; + height: 3px; + width: 110%; + margin-top: 0.5rem; + --bg-opacity: 1; + background-color: rgb(30 41 59/var(--bg-opacity)); +} +body.home .h1warp .warp-body p + p { + margin-top: 1.6rem; +} +body.home .h1warp .warp-body p { + text-indent: 2rem; +} + + +body.home .h1warp p { + text-align: left; +} + +.home-card { + display: grid; + gap: 2rem; + grid-template-columns: repeat(4,minmax(0,1fr)); +} +.home-card a { + display: flex; + align-items: center; + cursor: pointer; + border-radius: 0.5rem; + padding: 1rem; + color: rgb(30 41 59/1); + box-shadow: 0 0 #0000,0 0 #0000,0 1px 2px 0 rgba(0,0,0,0.05); + color: rgb(203 213 225/1); + --bg-opacity: 0.5; + background-color: rgb(62 69 72/var(--bg-opacity)); + transition: all .3s; +} +.home-card a:hover { + --bg-opacity: 1; +} + +.header-nav .max-container { + padding-top: 1.8rem; +} + +.header-nav .max-container, .header-nav .logo, .header-nav .menu, .header-nav .menu a { + display: flex; + justify-content: space-between; + align-items: center; +} + +.header-nav .logo { + gap: 0.5rem; + color: currentColor; +} + +.header-nav .title { + font-size: 1.8rem; + line-height: 2rem; + font-weight: bold; +} + +.header-nav .logo svg { + font-size: 40px; +} + +.header-nav .menu a:hover { + background-color: rgb(30 41 59/1); +} + +.header-nav .menu a { + padding-left: 0.75rem; + padding-right: 0.75rem; + padding-top: 0.5rem; + padding-bottom: 0.5rem; + border-radius: 9999px; + transition: all .3s; +} + +.header-nav .menu { + gap: 0.2rem; +} +.header-nav .menu a > span { + font-size: 0.9rem; +} + +.header-nav a, .header-nav a:visited { + color: rgb(209 213 219/1); + line-height: 1.2; + gap: 0.3rem; +} + +.warp-header.h1warp { + text-align: center; + margin-top: 4.6rem; + margin-bottom: 5rem; +} + +.warp-header.h1warp .warp-body { + color: rgb(71 85 105/1); +} + +.warp-header.h1warp > h1 { + font-size: 3rem; + line-height: 1; + margin-bottom: 3rem; +} + +.h1warp-body { + display: flex; + flex-direction: column; + gap: 3rem; +} + +.warp-header.h2warp > h2 { + margin: 0; + padding: 0; + margin-bottom: 24px; + position: relative; + font-size: 30px; + line-height: 1.2; + font-weight: 200; + font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Oxygen","Ubuntu","Cantarell","Fira Sans","Droid Sans","Helvetica Neue",sans-serif; + margin-top: 0; +} + +.warp-header.h3warp { + z-index: 0; + display: flex; + height: 100%; + width: 100%; + flex-direction: column; +} + +.warp-header.h3warp > h3 { + color: rgb(226 232 240/1); + position: absolute; + right: 0px; + top: 0px; + z-index: 10; + border-bottom-left-radius: 0.5rem; + background-color: #228e6c; + padding-left: 0.75rem; + padding-right: 0.75rem; + padding-top: 0.25rem; + padding-bottom: 0.25rem; + font-size: 0.75rem; + line-height: 1rem; + letter-spacing: 0.05em; +} + +.warp-header.h3warp > .warp-body p, .warp-header.h4warp > .warp-body p { + margin: 0px; + width: 100%; + padding-left: 1rem; + padding-right: 1rem; + padding-top: 0.75rem; + padding-bottom: 0.75rem; + color: rgb(148 163 184/1); + background-color: rgb(15 23 42/0.3); +} + +.warp-header.h3warp > .warp-body p:first-child:before { + background-color: rgb(15 23 42/0.3); + color: rgb(30 41 59/0); + content: '-'; + line-height: 1.75rem; + top: -4px; + position: absolute; + left: 0px; + width: 100%; +} + +.warp-header.h3warp > .warp-body p:last-child { + margin-top: auto; +} + +.warp-header.h3warp > .warp-body { + z-index: 0; + display: flex; + height: 100%; + width: 100%; + flex-direction: column; +} + +.h4warp > h4 { + border-color: rgb(51 65 85/0.5); + background-color: rgb(51 65 85/0.3); + color: rgb(203 213 225/1); + + margin: 0px; + border-top-width: 1px; + padding-left: 1rem; + padding-right: 1rem; + padding-top: 0.25rem; + padding-bottom: 0.25rem; + text-align: center; +} + +ol, ul, menu { + list-style: none; + margin: 0; + padding: 0; +} + +.h4warp > .warp-body ul, +.h4warp > .warp-body ol, +.h4warp > .warp-body dl, + +.h3warp > .warp-body ul, +.h3warp > .warp-body ol, +.h3warp > .warp-body dl { + margin-top: 0.5rem; + margin-bottom: 0.5rem; + display: grid; + list-style-position: outside; + grid-template-columns: repeat(1,minmax(0,1fr)); +} + +.h2warp-body ul li, +.h2warp-body ol li, +.h2warp-body dl li { + padding: 9px; + padding-left: 26px; + position: relative; + border-bottom: solid 1px rgb(51 65 85/0.5); +} + +.h2warp-body ul:not(.style-none)>li::before { + content: ''; + position: absolute; + display: inline-block; + width: 4px; + height: 4px; + background: #556677; + border-radius: 50%; + left: 13px; + top: 18px; +} + +.h2warp-body ul li, +.h2warp-body ol li, +.h2warp-body dl li { + position: relative; +} + +.warp-body ul:last-child { + margin-bottom: 0; +} + +.warp-body ul:last-child li:last-child { + border-bottom: 0; +} + +.h3warp hr { + border-bottom: 1px solid #475060; +} + +.h2warp-body { + display: grid; + gap: 1.75rem; + font-size: 0.925rem; + line-height: 1.325rem; + grid-template-columns: repeat(3,minmax(0,1fr)); + flex-direction: column; +} + +.h2warp-body > .warp { + background-color: #1e293b; + color: rgb(203 213 225/1); + position: relative; + display: flex; + flex-direction: column; + overflow: hidden; + border-radius: 0.5rem; + padding-top: 1.5rem; + box-shadow: 0 0 #0000, 0 0 #0000, 0 6px 8px rgba(102,119,136,0.03),0 1px 2px rgba(102,119,136,0.3); +} + +table { + text-indent: 0; + border-color: inherit; + border-collapse: collapse +} + + +table td:not(:last-child)>code, kbd { + background-color: rgb(51 65 85/0.5); + color: rgb(203 213 225/1); + box-shadow: 0 0 #0000, 0 0 #0000, 0 0 #0000; + letter-spacing: 0.075rem; + padding: 0.1em 0.54em; + border: 1px solid rgb(204,204,204); + border-color: rgb(51 65 85/1); + line-height: 1.6; + font-family: Arial,Helvetica,sans-serif; + font-size: 12px; + display: inline-block; + border-radius: 3px; +} + +table tr+tr { + border-top: solid 1px #ececec94; + border-color: rgb(51 65 85/0.5); +} + +table td:first-child { + white-space: nowrap; +} +table td, table th { + padding: 9px 14px; + text-align: left; +} +table tr th:last-child, table tr td:last-child { + text-align: right; +} + +table thead th { + white-space: nowrap; + font-weight: normal; + color: rgb(16 185 129/1); +} + +table thead { + display: table-header-group; + border-bottom: solid 1px rgba(85,102,119,0.3); +} + +.table-thead-hide thead { + display: none; +} + +tt, code { + font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; + font-size: 1em; +} +pre:only-child { + height: 100%; +} + +pre { + margin-top: 0; + margin-bottom: 0; + font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; + word-wrap: normal; + line-height: 1.5; + overflow: hidden; + padding: 1rem; +} + +.code-highlight { + display: block; + overflow-x: auto; +} + +.cols-1 { + grid-template-columns: repeat(1,minmax(0,1fr)); +} +.cols-2 { + grid-template-columns: repeat(2,minmax(0,1fr)); +} +.col-span-2 { + grid-column: span 2/span 2; +} +.col-span-3 { + grid-column: span 3/span 3; +} +.col-span-4 { + grid-column: span 4/span 4; +} +.row-span-2 { + grid-row: span 2/span 2; +} +.row-span-3 { + grid-row: span 3/span 3; +} +.row-span-4 { + grid-row: span 4/span 4; +} +.wrap { + white-space: pre-wrap !important; + overflow-wrap: break-word !important; +} + +[data-color-mode*='light'], [data-color-mode*='light'] body { + --color-prettylights-syntax-comment: #6e7781; + --color-prettylights-syntax-constant: #0550ae; + --color-prettylights-syntax-entity: #8250df; + --color-prettylights-syntax-storage-modifier-import: #24292f; + --color-prettylights-syntax-entity-tag: #116329; + --color-prettylights-syntax-keyword: #cf222e; + --color-prettylights-syntax-string: #0a3069; + --color-prettylights-syntax-variable: #953800; + --color-prettylights-syntax-brackethighlighter-unmatched: #82071e; + --color-prettylights-syntax-invalid-illegal-text: #f6f8fa; + --color-prettylights-syntax-invalid-illegal-bg: #82071e; + --color-prettylights-syntax-carriage-return-text: #f6f8fa; + --color-prettylights-syntax-carriage-return-bg: #cf222e; + --color-prettylights-syntax-string-regexp: #116329; + --color-prettylights-syntax-markup-list: #3b2300; + --color-prettylights-syntax-markup-heading: #0550ae; + --color-prettylights-syntax-markup-italic: #24292f; + --color-prettylights-syntax-markup-bold: #24292f; + --color-prettylights-syntax-markup-deleted-text: #82071e; + --color-prettylights-syntax-markup-deleted-bg: #FFEBE9; + --color-prettylights-syntax-markup-inserted-text: #116329; + --color-prettylights-syntax-markup-inserted-bg: #dafbe1; + --color-prettylights-syntax-markup-changed-text: #953800; + --color-prettylights-syntax-markup-changed-bg: #ffd8b5; + --color-prettylights-syntax-markup-ignored-text: #eaeef2; + --color-prettylights-syntax-markup-ignored-bg: #0550ae; + --color-prettylights-syntax-meta-diff-range: #8250df; + --color-prettylights-syntax-brackethighlighter-angle: #57606a; + --color-prettylights-syntax-sublimelinter-gutter-mark: #8c959f; + --color-prettylights-syntax-constant-other-reference-link: #0a3069; + --color-fg-default: #24292f; + --color-fg-muted: #57606a; + --color-fg-subtle: #6e7781; + --color-canvas-default: #ffffff; + --color-canvas-subtle: #f6f8fa; + --color-border-default: #d0d7de; + --color-border-muted: hsla(210,18%,87%,1); + --color-neutral-muted: rgba(175,184,193,0.2); + --color-accent-fg: #0969da; + --color-accent-emphasis: #0969da; + --color-attention-subtle: #fff8c5; + --color-danger-fg: #cf222e; +} + +[data-color-mode*='dark'], [data-color-mode*='dark'] body { + --color-prettylights-syntax-comment: #8b949e; + --color-prettylights-syntax-constant: #79c0ff; + --color-prettylights-syntax-entity: #d2a8ff; + --color-prettylights-syntax-storage-modifier-import: #c9d1d9; + --color-prettylights-syntax-entity-tag: #7ee787; + --color-prettylights-syntax-keyword: #ff7b72; + --color-prettylights-syntax-string: #a5d6ff; + --color-prettylights-syntax-variable: #ffa657; + --color-prettylights-syntax-brackethighlighter-unmatched: #f85149; + --color-prettylights-syntax-invalid-illegal-text: #f0f6fc; + --color-prettylights-syntax-invalid-illegal-bg: #8e1519; + --color-prettylights-syntax-carriage-return-text: #f0f6fc; + --color-prettylights-syntax-carriage-return-bg: #b62324; + --color-prettylights-syntax-string-regexp: #7ee787; + --color-prettylights-syntax-markup-list: #f2cc60; + --color-prettylights-syntax-markup-heading: #1f6feb; + --color-prettylights-syntax-markup-italic: #c9d1d9; + --color-prettylights-syntax-markup-bold: #c9d1d9; + --color-prettylights-syntax-markup-deleted-text: #ffdcd7; + --color-prettylights-syntax-markup-deleted-bg: #67060c; + --color-prettylights-syntax-markup-inserted-text: #aff5b4; + --color-prettylights-syntax-markup-inserted-bg: #033a16; + --color-prettylights-syntax-markup-changed-text: #ffdfb6; + --color-prettylights-syntax-markup-changed-bg: #5a1e02; + --color-prettylights-syntax-markup-ignored-text: #c9d1d9; + --color-prettylights-syntax-markup-ignored-bg: #1158c7; + --color-prettylights-syntax-meta-diff-range: #d2a8ff; + --color-prettylights-syntax-brackethighlighter-angle: #8b949e; + --color-prettylights-syntax-sublimelinter-gutter-mark: #484f58; + --color-prettylights-syntax-constant-other-reference-link: #a5d6ff; + --color-fg-default: #c9d1d9; + --color-fg-muted: #8b949e; + --color-fg-subtle: #484f58; + --color-canvas-default: #0d1117; + --color-canvas-subtle: #161b22; + --color-border-default: #30363d; + --color-border-muted: #21262d; + --color-neutral-muted: rgba(110,118,129,0.4); + --color-accent-fg: #58a6ff; + --color-accent-emphasis: #1f6feb; + --color-attention-subtle: rgba(187,128,9,0.15); + --color-danger-fg: #f85149; +} + +/* 代码高亮 Start */ +.token.comment, .token.prolog, .token.doctype, .token.cdata { + color: var(--color-prettylights-syntax-comment); +} +.token.namespace { opacity: 0.7; } +.token.tag, .token.selector, .token.constant, .token.symbol, .token.deleted { + color: var(--color-prettylights-syntax-entity-tag); +} +.token.maybe-class-name { + color: var(--color-prettylights-syntax-variable); +} +.token.property-access, .token.operator, .token.boolean, .token.number, .token.selector .token.class, .token.attr-name, .token.string, .token.char, .token.builtin { + color: var(--color-prettylights-syntax-constant); +} +.token.deleted { + color: var(--color-prettylights-syntax-markup-deleted-text); +} +.token.property { + color: var(--color-prettylights-syntax-constant); +} +.token.punctuation { + color: var(--color-prettylights-syntax-markup-bold); +} +.token.function { + color: var(--color-prettylights-syntax-entity); +} +.code-line .token.deleted { + background-color: var(--color-prettylights-syntax-markup-deleted-bg); +} +.token.inserted { + color: var(--color-prettylights-syntax-markup-inserted-text); +} +.code-line .token.inserted { + background-color: var(--color-prettylights-syntax-markup-inserted-bg); +} + +.token.variable { + color: var(--color-prettylights-syntax-constant); +} +.token.entity, .token.url, .language-css .token.string, .style .token.string { + color: var(--color-prettylights-syntax-string); +} +.token.color, .token.atrule, .token.attr-value, .token.function, .token.class-name { + color: var(--color-prettylights-syntax-string); +} +.token.rule, .token.regex, .token.important, .token.keyword { + color: var(--color-prettylights-syntax-keyword); +} +.token.coord { + color: var(--color-prettylights-syntax-meta-diff-range); +} + +.token.number { + color: var(--color-accent-emphasis); +} +.token.string { + color: var(--color-prettylights-syntax-string); +} +.token.boolean { + color: var(--color-prettylights-syntax-markup-heading); +} +.token.property-access { + color: var(--color-prettylights-syntax-variable); +} + +.token.important, .token.bold { font-weight: bold; } +.token.italic { font-style: italic; } +.token.entity { cursor: help; } + +/* 代码高亮 End */ + + +.footer-warp { + margin-top: 3.5rem; + color: rgb(100 116 139/1); + background-color: rgb(30 41 59/1); + text-align: center; +} \ No newline at end of file