From ce6a2200e3517cbaed47eff535feedbadfe9f88b Mon Sep 17 00:00:00 2001 From: jaywcjlove Date: Wed, 5 Oct 2022 06:47:35 +0000 Subject: [PATCH] doc: Update `react.md` cheatsheet. a723b97df5cb22a401786eea58675d6612fb6860 --- docs/bash.html | 654 ++++++------- docs/chmod.html | 104 +- docs/cron.html | 18 +- docs/docker.html | 110 +-- docs/dockerfile.html | 116 +-- docs/find.html | 104 +- docs/git.html | 274 +++--- docs/javascript.html | 1956 +++++++++++++++++++------------------- docs/jest.html | 720 +++++++------- docs/json.html | 290 +++--- docs/markdown.html | 134 +-- docs/npm.html | 10 +- docs/package.json.html | 448 ++++----- docs/quickreference.html | 380 ++++---- docs/react.html | 1140 +++++++++++----------- docs/regex.html | 344 +++---- docs/sed.html | 92 +- docs/semver.html | 12 +- docs/ssh.html | 64 +- docs/toml.html | 220 ++--- docs/typescript.html | 1312 ++++++++++++------------- docs/vim.html | 166 ++-- docs/xpath.html | 160 ++-- style/style.css | 13 + 24 files changed, 4436 insertions(+), 4405 deletions(-) diff --git a/docs/bash.html b/docs/bash.html index ceea2a66..e9e029d7 100644 --- a/docs/bash.html +++ b/docs/bash.html @@ -38,30 +38,30 @@

这是开始使用 linux bash shell 脚本的快速参考备忘单。

入门

hello.sh

-
#!/bin/bash
-VAR="world"
-echo "Hello $VAR!" # => Hello world!
+
#!/bin/bash
+VAR="world"
+echo "Hello $VAR!" # => Hello world!
 

执行脚本

-
$ bash hello.sh
+
$ bash hello.sh
 

变量

-
NAME="John"
-echo ${NAME}    # => John (变量)
-echo $NAME      # => John (变量)
-echo "$NAME"    # => John (变量)
-echo '$NAME'    # => $NAME (确切的字符串)
-echo "${NAME}!" # => John! (变量)
-NAME = "John"   # => Error (关于空间)
+
NAME="John"
+echo ${NAME}    # => John (变量)
+echo $NAME      # => John (变量)
+echo "$NAME"    # => John (变量)
+echo '$NAME'    # => $NAME (确切的字符串)
+echo "${NAME}!" # => John! (变量)
+NAME = "John"   # => Error (关于空间)
 

注释

-
# 这是一个内联 Bash 注释。
+
# 这是一个内联 Bash 注释。
 
-
: '
-这是一个
-非常整洁的评论
-在 bash
-'
+
: '
+这是一个
+非常整洁的评论
+在 bash
+'
 

多行注释使用 :' 打开和 ' 关闭

参数

@@ -118,22 +118,22 @@
表示描述
$1$9参数 1 ... 9
$0脚本本身的名称
$1第一个论点
${10}位置参数 10
$#参数数量
$$shell 的进程 id
$*所有论据
$@所有参数,从第一个开始
$-当前选项
$_上一个命令的最后一个参数

见:特殊参数

函数

-
get_name() {
-    echo "John"
-}
-echo "You are $(get_name)"
+
get_name() {
+    echo "John"
+}
+echo "You are $(get_name)"
 

见:函数

条件句

-
if [[ -z "$string" ]]; then
-    echo "String is empty"
-elif [[ -n "$string" ]]; then
-    echo "String is not empty"
-fi
+
if [[ -z "$string" ]]; then
+    echo "String is empty"
+elif [[ -n "$string" ]]; then
+    echo "String is not empty"
+fi
 

见:条件句

大括号扩展

-
echo {A,B}.js
+
echo {A,B}.js
 

@@ -160,10 +160,10 @@
表示描述
{A,B}A B 相同
{A,B}.jsA.js B.js 相同
{1..5}1 2 3 4 5 相同

见:大括号扩展

Shell 执行

-
# => I'm in /当前/的/路径
-echo "I'm in $(PWD)"
-# Same as:
-echo "I'm in `pwd`"
+
# => I'm in /当前/的/路径
+echo "I'm in $(PWD)"
+# Same as:
+echo "I'm in `pwd`"
 

见:命令替换

Bash 参数扩展

@@ -273,71 +273,71 @@
表示描述
${FOO:-val}$FOO,如果未设置,则为 val
${FOO:=val}如果未设置,则将 $FOO 设置为 val
${FOO:+val}val 如果设置了$FOO
${FOO:?message}如果 $FOO 未设置,则显示消息并退出

替代 Substitution

-
echo ${food:-Cake}  #=> $food or "Cake"
+
echo ${food:-Cake}  #=> $food or "Cake"
 
-
STR="/path/to/foo.cpp"
-echo ${STR%.cpp}    # /path/to/foo
-echo ${STR%.cpp}.o  # /path/to/foo.o
-echo ${STR%/*}      # /path/to
-echo ${STR##*.}     # cpp (extension)
-echo ${STR##*/}     # foo.cpp (basepath)
-echo ${STR#*/}      # path/to/foo.cpp
-echo ${STR##*/}     # foo.cpp
-echo ${STR/foo/bar} # /path/to/bar.cpp
+
STR="/path/to/foo.cpp"
+echo ${STR%.cpp}    # /path/to/foo
+echo ${STR%.cpp}.o  # /path/to/foo.o
+echo ${STR%/*}      # /path/to
+echo ${STR##*.}     # cpp (extension)
+echo ${STR##*/}     # foo.cpp (basepath)
+echo ${STR#*/}      # path/to/foo.cpp
+echo ${STR##*/}     # foo.cpp
+echo ${STR/foo/bar} # /path/to/bar.cpp
 

切片 Slicing

-
name="John"
-echo ${name}           # => John
-echo ${name:0:2}       # => Jo
-echo ${name::2}        # => Jo
-echo ${name::-1}       # => Joh
-echo ${name:(-1)}      # => n
-echo ${name:(-2)}      # => hn
-echo ${name:(-2):2}    # => hn
-
-length=2
-echo ${name:0:length}  # => Jo
+
name="John"
+echo ${name}           # => John
+echo ${name:0:2}       # => Jo
+echo ${name::2}        # => Jo
+echo ${name::-1}       # => Joh
+echo ${name:(-1)}      # => n
+echo ${name:(-2)}      # => hn
+echo ${name:(-2):2}    # => hn
+
+length=2
+echo ${name:0:length}  # => Jo
 

见:参数扩展

基本路径和目录路径

-
SRC="/path/to/foo.cpp"
+
SRC="/path/to/foo.cpp"
 
-
BASEPATH=${SRC##*/}   
-echo $BASEPATH  # => "foo.cpp"
-
-DIRPATH=${SRC%$BASEPATH}
-echo $DIRPATH   # => "/path/to/"
+
BASEPATH=${SRC##*/}   
+echo $BASEPATH  # => "foo.cpp"
+
+DIRPATH=${SRC%$BASEPATH}
+echo $DIRPATH   # => "/path/to/"
 

Transform

-
STR="HELLO WORLD!"
-echo ${STR,}      # => hELLO WORLD!
-echo ${STR,,}     # => hello world!
-
-STR="hello world!"
-echo ${STR^}      # => Hello world!
-echo ${STR^^}     # => HELLO WORLD!
-
-ARR=(hello World)
-echo "${ARR[@],}" # => hello world
-echo "${ARR[@]^}" # => Hello World
+
STR="HELLO WORLD!"
+echo ${STR,}      # => hELLO WORLD!
+echo ${STR,,}     # => hello world!
+
+STR="hello world!"
+echo ${STR^}      # => Hello world!
+echo ${STR^^}     # => HELLO WORLD!
+
+ARR=(hello World)
+echo "${ARR[@],}" # => hello world
+echo "${ARR[@]^}" # => Hello World
 

Bash 数组

定义数组

-
Fruits=('Apple' 'Banana' 'Orange')
-
-Fruits[0]="Apple"
-Fruits[1]="Banana"
-Fruits[2]="Orange"
-
-ARRAY1=(foo{1..2}) # => foo1 foo2
-ARRAY2=({A..D})    # => A B C D
-
-# 合并 => foo1 foo2 A B C D
-ARRAY3=(${ARRAY1[@]} ${ARRAY2[@]})
-
-# 声明构造
-declare -a Numbers=(1 2 3)
-Numbers+=(4 5) # 附加 => 1 2 3 4 5
+
Fruits=('Apple' 'Banana' 'Orange')
+
+Fruits[0]="Apple"
+Fruits[1]="Banana"
+Fruits[2]="Orange"
+
+ARRAY1=(foo{1..2}) # => foo1 foo2
+ARRAY2=({A..D})    # => A B C D
+
+# 合并 => foo1 foo2 A B C D
+ARRAY3=(${ARRAY1[@]} ${ARRAY2[@]})
+
+# 声明构造
+declare -a Numbers=(1 2 3)
+Numbers+=(4 5) # 附加 => 1 2 3 4 5
 

索引

@@ -387,61 +387,61 @@
:--
${Fruits[0]}第一个元素
${Fruits[-1]}最后一个元素
${Fruits[*]}所有元素
${Fruits[@]}所有元素
${#Fruits[@]}总数
${#Fruits}第一节长度
${#Fruits[3]}第n个长度
${Fruits[@]:3:2}范围
${!Fruits[@]}所有 Key

迭代 Iteration

-
Fruits=('Apple' 'Banana' 'Orange')
-for e in "${Fruits[@]}"; do
-    echo $e
-done
+
Fruits=('Apple' 'Banana' 'Orange')
+for e in "${Fruits[@]}"; do
+    echo $e
+done
 

With index

-
for i in "${!Fruits[@]}"; do
-  printf "%s\t%s\n" "$i" "${Fruits[$i]}"
-done
+
for i in "${!Fruits[@]}"; do
+  printf "%s\t%s\n" "$i" "${Fruits[$i]}"
+done
 

操作

-
Fruits=("${Fruits[@]}" "Watermelon")         # 推
-Fruits+=('Watermelon')                       # 也推
-Fruits=( ${Fruits[@]/Ap*/} )                 # 通过正则表达式匹配删除
-unset Fruits[2]                              # 删除一项
-Fruits=("${Fruits[@]}")                      # 复制
-Fruits=("${Fruits[@]}" "${Veggies[@]}")      # 连接
-lines=(`cat "logfile"`)                      # 从文件中读取
+
Fruits=("${Fruits[@]}" "Watermelon")         # 推
+Fruits+=('Watermelon')                       # 也推
+Fruits=( ${Fruits[@]/Ap*/} )                 # 通过正则表达式匹配删除
+unset Fruits[2]                              # 删除一项
+Fruits=("${Fruits[@]}")                      # 复制
+Fruits=("${Fruits[@]}" "${Veggies[@]}")      # 连接
+lines=(`cat "logfile"`)                      # 从文件中读取
 

数组作为参数

-
function extract()
-{
-  local -n myarray=$1
-  local idx=$2
-  echo "${myarray[$idx]}"
-}
-Fruits=('Apple' 'Banana' 'Orange')
-extract Fruits 2     # => Orangle
+
function extract()
+{
+  local -n myarray=$1
+  local idx=$2
+  echo "${myarray[$idx]}"
+}
+Fruits=('Apple' 'Banana' 'Orange')
+extract Fruits 2     # => Orangle
 

Bash 字典

定义

-
declare -A sounds
+
declare -A sounds
 
-
sounds[dog]="bark"
-sounds[cow]="moo"
-sounds[bird]="tweet"
-sounds[wolf]="howl"
+
sounds[dog]="bark"
+sounds[cow]="moo"
+sounds[bird]="tweet"
+sounds[wolf]="howl"
 

使用字典

-
echo ${sounds[dog]} # Dog's sound
-echo ${sounds[@]}   # All values
-echo ${!sounds[@]}  # All keys
-echo ${#sounds[@]}  # Number of elements
-unset sounds[dog]   # Delete dog
+
echo ${sounds[dog]} # Dog's sound
+echo ${sounds[@]}   # All values
+echo ${!sounds[@]}  # All keys
+echo ${#sounds[@]}  # Number of elements
+unset sounds[dog]   # Delete dog
 

迭代

-
for val in "${sounds[@]}"; do
-    echo $val
-done
+
for val in "${sounds[@]}"; do
+    echo $val
+done
 

-
for key in "${!sounds[@]}"; do
-    echo $key
-done
+
for key in "${!sounds[@]}"; do
+    echo $key
+done
 

Bash 条件句

整数条件

@@ -541,38 +541,38 @@

例子

字符串

-
if [[ -z "$string" ]]; then
-    echo "String is empty"
-elif [[ -n "$string" ]]; then
-    echo "String is not empty"
-else
-    echo "This never happens"
-fi
+
if [[ -z "$string" ]]; then
+    echo "String is empty"
+elif [[ -n "$string" ]]; then
+    echo "String is not empty"
+else
+    echo "This never happens"
+fi
 

组合

-
if [[ X && Y ]]; then
-    ...
-fi
+
if [[ X && Y ]]; then
+    ...
+fi
 

相等

-
if [[ "$A" == "$B" ]]; then
-    ...
-fi
+
if [[ "$A" == "$B" ]]; then
+    ...
+fi
 

正则表达式

-
if [[ '1. abc' =~ ([a-z]+) ]]; then
-    echo ${BASH_REMATCH[1]}
-fi
+
if [[ '1. abc' =~ ([a-z]+) ]]; then
+    echo ${BASH_REMATCH[1]}
+fi
 

更小

-
if (( $a < $b )); then
-   echo "$a is smaller than $b"
-fi
+
if (( $a < $b )); then
+   echo "$a is smaller than $b"
+fi
 

存在

-
if [[ -e "file.txt" ]]; then
-    echo "file exists"
-fi
+
if [[ -e "file.txt" ]]; then
+    echo "file exists"
+fi
 

文件条件

@@ -658,156 +658,156 @@
条件描述
[[ -o noclobber ]]如果启用 OPTION
[[ ! EXPR ]]不是 Not
[[ X && Y ]]和 And
[[ X || Y ]]或者 Or

逻辑和,或

-
if [ "$1" = 'y' -a $2 -gt 0 ]; then
-    echo "yes"
-fi
-if [ "$1" = 'n' -o $2 -lt 0 ]; then
-    echo "no"
-fi
+
if [ "$1" = 'y' -a $2 -gt 0 ]; then
+    echo "yes"
+fi
+if [ "$1" = 'n' -o $2 -lt 0 ]; then
+    echo "no"
+fi
 

Bash 循环

基本 for 循环

-
for i in /etc/rc.*; do
-    echo $i
-done
+
for i in /etc/rc.*; do
+    echo $i
+done
 

类似 C 的 for 循环

-
for ((i = 0 ; i < 100 ; i++)); do
-    echo $i
-done
+
for ((i = 0 ; i < 100 ; i++)); do
+    echo $i
+done
 

范围

-
for i in {1..5}; do
-    echo "Welcome $i"
-done
+
for i in {1..5}; do
+    echo "Welcome $i"
+done
 

具有步长

-
for i in {5..50..5}; do
-    echo "Welcome $i"
-done
+
for i in {5..50..5}; do
+    echo "Welcome $i"
+done
 

自动递增

-
i=1
-while [[ $i -lt 4 ]]; do
-    echo "Number: $i"
-    ((i++))
-done
+
i=1
+while [[ $i -lt 4 ]]; do
+    echo "Number: $i"
+    ((i++))
+done
 

自动递增

-
i=3
-while [[ $i -gt 0 ]]; do
-    echo "Number: $i"
-    ((i--))
-done
+
i=3
+while [[ $i -gt 0 ]]; do
+    echo "Number: $i"
+    ((i--))
+done
 

Continue

-
for number in $(seq 1 3); do
-    if [[ $number == 2 ]]; then
-        continue;
-    fi
-    echo "$number"
-done
+
for number in $(seq 1 3); do
+    if [[ $number == 2 ]]; then
+        continue;
+    fi
+    echo "$number"
+done
 

Break

-
for number in $(seq 1 3); do
-    if [[ $number == 2 ]]; then
-        # Skip entire rest of loop.
-        break;
-    fi
-    # This will only print 1
-    echo "$number"
-done
+
for number in $(seq 1 3); do
+    if [[ $number == 2 ]]; then
+        # Skip entire rest of loop.
+        break;
+    fi
+    # This will only print 1
+    echo "$number"
+done
 

Until

-
count=0
-until [ $count -gt 10 ]; do
-    echo "$count"
-    ((count++))
-done
+
count=0
+until [ $count -gt 10 ]; do
+    echo "$count"
+    ((count++))
+done
 

永远

-
while true; do
-    # here is some code.
-done
+
while true; do
+    # here is some code.
+done
 

永远(简写)

-
while :; do
-    # here is some code.
-done
+
while :; do
+    # here is some code.
+done
 

正在读取行

-
cat file.txt | while read line; do
-    echo $line
-done
+
cat file.txt | while read line; do
+    echo $line
+done
 

Bash 函数

定义函数

-
myfunc() {
-  echo "hello $1"
-}
+
myfunc() {
+  echo "hello $1"
+}
 
-
# 同上(替代语法)
-function myfunc() {
-  echo "hello $1"
-}
+
# 同上(替代语法)
+function myfunc() {
+  echo "hello $1"
+}
 
-
myfunc "John"
+
myfunc "John"
 

返回值

-
myfunc() {
-    local myresult='some value'
-    echo $myresult
-}
+
myfunc() {
+    local myresult='some value'
+    echo $myresult
+}
 
-
result="$(myfunc)"
+
result="$(myfunc)"
 

正在引发错误

-
myfunc() {
-    return 1
-}
+
myfunc() {
+    return 1
+}
 
-
if myfunc; then
-    echo "success"
-else
-    echo "failure"
-fi
+
if myfunc; then
+    echo "success"
+else
+    echo "failure"
+fi
 

Bash 选项

选项

-
# 避免覆盖文件
-# (echo "hi" > foo)
-set -o noclobber
-
-# 用于出错时退出
-# 避免级联错误
-set -o errexit   
-
-# 揭示隐藏的失败
-set -o pipefail  
-
-# 公开未设置的变量
-set -o nounset
+
# 避免覆盖文件
+# (echo "hi" > foo)
+set -o noclobber
+
+# 用于出错时退出
+# 避免级联错误
+set -o errexit   
+
+# 揭示隐藏的失败
+set -o pipefail  
+
+# 公开未设置的变量
+set -o nounset
 

全局选项

-
# 不匹配的 glob 被删除
-# ('*.foo' => '')
-shopt -s nullglob   
-
-# 不匹配的 glob 抛出错误
-shopt -s failglob  
-
-# 不区分大小写的球体
-shopt -s nocaseglob 
-
-# 通配符匹配点文件
-# ("*.sh" => ".foo.sh")
-shopt -s dotglob    
-
-# 允许 ** 进行递归匹配
-# ('lib/**/*.rb' => 'lib/a/b/c.rb')
-shopt -s globstar   
+
# 不匹配的 glob 被删除
+# ('*.foo' => '')
+shopt -s nullglob   
+
+# 不匹配的 glob 抛出错误
+shopt -s failglob  
+
+# 不区分大小写的球体
+shopt -s nocaseglob 
+
+# 通配符匹配点文件
+# ("*.sh" => ".foo.sh")
+shopt -s dotglob    
+
+# 允许 ** 进行递归匹配
+# ('lib/**/*.rb' => 'lib/a/b/c.rb')
+shopt -s globstar   
 

Bash 历史

@@ -931,87 +931,87 @@

!! 可以替换为任何有效的扩展,即 !cat!-2!42 等。

各种各样的

数值计算

-
$((a + 200))      # Add 200 to $a
+
$((a + 200))      # Add 200 to $a
 
-
$(($RANDOM%200))  # Random number 0..199
+
$(($RANDOM%200))  # Random number 0..199
 

子 shell

-
(cd somedir; echo "I'm now in $PWD")
-pwd # still in first directory
+
(cd somedir; echo "I'm now in $PWD")
+pwd # still in first directory
 

检查命令

-
command -V cd
-#=> "cd is a function/alias/whatever"
+
command -V cd
+#=> "cd is a function/alias/whatever"
 

重定向

-
python hello.py > output.txt   # 标准输出到(文件)
-python hello.py >> output.txt  # 标准输出到(文件),追加
-python hello.py 2> error.log   # 标准错误到(文件)
-python hello.py 2>&1           # 标准错误到标准输出
-python hello.py 2>/dev/null    # 标准错误到(空null)
-python hello.py &>/dev/null    # 标准输出和标准错误到(空null)
+
python hello.py > output.txt   # 标准输出到(文件)
+python hello.py >> output.txt  # 标准输出到(文件),追加
+python hello.py 2> error.log   # 标准错误到(文件)
+python hello.py 2>&1           # 标准错误到标准输出
+python hello.py 2>/dev/null    # 标准错误到(空null)
+python hello.py &>/dev/null    # 标准输出和标准错误到(空null)
 
-
python hello.py < foo.txt      # 将 foo.txt 提供给 python 的标准输入
+
python hello.py < foo.txt      # 将 foo.txt 提供给 python 的标准输入
 

来源相对

-
source "${0%/*}/../share/foo.sh"
+
source "${0%/*}/../share/foo.sh"
 

脚本目录

-
DIR="${0%/*}"
+
DIR="${0%/*}"
 

Case/switch

-
case "$1" in
-    start | up)
-    vagrant up
-    ;;
-    *)
-    echo "Usage: $0 {start|stop|ssh}"
-    ;;
-esac
+
case "$1" in
+    start | up)
+    vagrant up
+    ;;
+    *)
+    echo "Usage: $0 {start|stop|ssh}"
+    ;;
+esac
 

陷阱错误

-
trap 'echo Error at about $LINENO' ERR
+
trap 'echo Error at about $LINENO' ERR
 

或者

-
traperr() {
-    echo "ERROR: ${BASH_SOURCE[1]} at about ${BASH_LINENO[0]}"
-}
-set -o errtrace
-trap traperr ERR
+
traperr() {
+    echo "ERROR: ${BASH_SOURCE[1]} at about ${BASH_LINENO[0]}"
+}
+set -o errtrace
+trap traperr ERR
 

printf

-
printf "Hello %s, I'm %s" Sven Olga
-#=> "Hello Sven, I'm Olga
-
-printf "1 + 1 = %d" 2
-#=> "1 + 1 = 2"
-
-printf "Print a float: %f" 2
-#=> "Print a float: 2.000000"
+
printf "Hello %s, I'm %s" Sven Olga
+#=> "Hello Sven, I'm Olga
+
+printf "1 + 1 = %d" 2
+#=> "1 + 1 = 2"
+
+printf "Print a float: %f" 2
+#=> "Print a float: 2.000000"
 

获取选项

-
while [[ "$1" =~ ^- && ! "$1" == "--" ]]; do case $1 in
-    -V | --version )
-    echo $version
-    exit
-    ;;
-    -s | --string )
-    shift; string=$1
-    ;;
-    -f | --flag )
-    flag=1
-    ;;
-esac; shift; done
-if [[ "$1" == '--' ]]; then shift; fi
+
while [[ "$1" =~ ^- && ! "$1" == "--" ]]; do case $1 in
+    -V | --version )
+    echo $version
+    exit
+    ;;
+    -s | --string )
+    shift; string=$1
+    ;;
+    -f | --flag )
+    flag=1
+    ;;
+esac; shift; done
+if [[ "$1" == '--' ]]; then shift; fi
 

检查命令的结果

-
if ping -c 1 google.com; then
-    echo "看来您的互联网连接正常"
-fi
+
if ping -c 1 google.com; then
+    echo "看来您的互联网连接正常"
+fi
 

特殊变量

@@ -1044,9 +1044,9 @@

特殊参数

grep 检查

-
if grep -q 'foo' ~/.bash_history; then
-    echo "您过去似乎输入过“foo”"
-fi
+
if grep -q 'foo' ~/.bash_history; then
+    echo "您过去似乎输入过“foo”"
+fi
 

反斜杠转义

@@ -1078,38 +1078,38 @@

使用 \ 转义这些特殊字符

Heredoc

-
cat <<END
-hello world
-END
+
cat <<END
+hello world
+END
 

转到上一个目录

-
pwd # /home/user/foo
-cd bar/
-pwd # /home/user/foo/bar
-cd -
-pwd # /home/user/foo
+
pwd # /home/user/foo
+cd bar/
+pwd # /home/user/foo/bar
+cd -
+pwd # /home/user/foo
 

读取输入

-
echo -n "Proceed? [y/n]: "
-read ans
-echo $ans
+
echo -n "Proceed? [y/n]: "
+read ans
+echo $ans
 
-
read -n 1 ans    # 只有一个字符
+
read -n 1 ans    # 只有一个字符
 

条件执行

-
git commit && git push
-git commit || echo "Commit failed"
+
git commit && git push
+git commit || echo "Commit failed"
 

严格模式

-
set -euo pipefail
-IFS=$'\n\t'
+
set -euo pipefail
+IFS=$'\n\t'
 

参见:非官方 bash 严格模式

可选参数

-
args=("$@")
-args+=(foo)
-args+=(bar)
-echo "${args[@]}"
+
args=("$@")
+args+=(foo)
+args+=(bar)
+echo "${args[@]}"
 

将参数放入数组中,然后追加

另见

diff --git a/docs/chmod.html b/docs/chmod.html index fb4aaf86..b763df4d 100644 --- a/docs/chmod.html +++ b/docs/chmod.html @@ -38,16 +38,16 @@

这份快速参考备忘单提供了文件权限的简要概述,以及 chmod 命令的操作

入门

语法

-
$ chmod [options] <permissions> <file> 
+
$ chmod [options] <permissions> <file> 
 

示例

-
$ chmod 755 foo.txt
-$ chmod +x quickref.py
-$ chmod u-x quickref.py
-$ chmod u=rwx,g=rx,o= quickref.sh
+
$ chmod 755 foo.txt
+$ chmod +x quickref.py
+$ chmod u-x quickref.py
+$ chmod u=rwx,g=rx,o= quickref.sh
 

递归更改文件和目录

-
$ chmod -R 755 my_directory
+
$ chmod -R 755 my_directory
 

chmod 命令代表“更改模式”

Chmod 生成器

@@ -111,18 +111,18 @@
命令s含义
400r--------仅所有者可读
500r-x------避免改变
600rw-------可由用户更改
644rw-r--r--由用户读取和更改
660rw-rw----可由用户和组更改
700rwx------只有用户具有完全访问权限
755rwxr-xr-x只能由用户更改
775rwxrwxr-x群组共享模式
777rwxrwxrwx每个人都可以做任何事

解释

-
$ ls -l
--rw-r--r--  1 root root 3 Jun 29 15:35 a.log
-drwxr-xr-x  2 root root 2 Jun 30 18:06 dir
+
$ ls -l
+-rw-r--r--  1 root root 3 Jun 29 15:35 a.log
+drwxr-xr-x  2 root root 2 Jun 30 18:06 dir
 

dir 的权限分析

-
d  rwx  r-x  r-x
-┬  ─┬─  ─┬─  ─┬─  
-┆   ┆    ┆    ┆  
-┆   ┆    ┆    ╰─ 4. Other|5 (4+0+1)
-┆   ┆    ╰────── 3. Group|5 (4+0+1)
-┆   ╰─────────── 2. User |7 (4+2+1)
-╰─────────────── 1. File Type | directory
+
d  rwx  r-x  r-x
+┬  ─┬─  ─┬─  ─┬─  
+┆   ┆    ┆    ┆  
+┆   ┆    ┆    ╰─ 4. Other|5 (4+0+1)
+┆   ┆    ╰────── 3. Group|5 (4+0+1)
+┆   ╰─────────── 2. User |7 (4+2+1)
+╰─────────────── 1. File Type | directory
 

权限模式

@@ -297,79 +297,79 @@
SymbolDescription
+添加
-删除
=设置

chmod 600

-
$ chmod 600 example.txt
-$ chmod u=rw,g=,o= example.txt
-$ chmod a+rwx,u-x,g-rwx,o-rwx example.txt
+
$ chmod 600 example.txt
+$ chmod u=rw,g=,o= example.txt
+$ chmod a+rwx,u-x,g-rwx,o-rwx example.txt
 

chmod 664

-
$ chmod 664 example.txt
-$ chmod u=rw,g=rw,o=r example.txt
-$ chmod a+rwx,u-x,g-x,o-wx example.txt
+
$ chmod 664 example.txt
+$ chmod u=rw,g=rw,o=r example.txt
+$ chmod a+rwx,u-x,g-x,o-wx example.txt
 

chmod 777

-
$ chmod 777 example.txt
-$ chmod u=rwx,g=rwx,o=rwx example.txt
-$ chmod a=rwx example.txt
+
$ chmod 777 example.txt
+$ chmod u=rwx,g=rwx,o=rwx example.txt
+$ chmod a=rwx example.txt
 

符号模式

拒绝所有人的执行权限。

-
$ chmod a-x chmodExampleFile.txt
+
$ chmod a-x chmodExampleFile.txt
 

向所有人授予读取权限。

-
$ chmod a+r chmodExampleFile.txt
+
$ chmod a+r chmodExampleFile.txt
 

使文件可由组和其他人读写。

-
$ chmod go+rw chmodExampleFile.txt
+
$ chmod go+rw chmodExampleFile.txt
 

使用户/所有者可执行 shell。

-
$ chmod u+x chmodExampleScript.sh
+
$ chmod u+x chmodExampleScript.sh
 

允许每个人读取、写入和执行文件并打开设置的 group-ID。

-
$ chmod =rwx,g+s chmodExampleScript.sh
+
$ chmod =rwx,g+s chmodExampleScript.sh
 

删除权限

要删除赋予文件的读写权限,请使用以下语法:

-
$ chmod o-rw example.txt
+
$ chmod o-rw example.txt
 

对于我们的文件 example.txt,我们可以通过运行以下命令使用 chmod for group 删除读写权限:

-
$ chmod  g-rx example.txt
+
$ chmod  g-rx example.txt
 

要从组中删除 chmod 读写权限,同时向 public/others 添加读写权限,我们可以使用以下命令:

-
$ chmod g-rx, o+rx example.txt
+
$ chmod g-rx, o+rx example.txt
 

但是,如果你想删除组和其他人的所有权限,你可以使用 go= 来代替:

-
$ chmod go= example.txt
+
$ chmod go= example.txt
 

可执行文件

-
$ chmod +x ~/example.py
-$ chmod u+x ~/example.py
-$ chmod a+x ~/example.py
+
$ chmod +x ~/example.py
+$ chmod u+x ~/example.py
+$ chmod a+x ~/example.py
 

chmod 754

-
$ chmod 754 foo.sh
-$ chmod u=rwx,g=rx,o=r foo.sh
+
$ chmod 754 foo.sh
+$ chmod u=rwx,g=rx,o=r foo.sh
 

Chmod 实践

SSH 权限

-
$ chmod 700 ~/.ssh
-$ chmod 600 ~/.ssh/authorized_keys
-$ chmod 600 ~/.ssh/id_rsa
-$ chmod 600 ~/.ssh/id_rsa.pub
-$ chmod 400 /path/to/access_key.pem
+
$ chmod 700 ~/.ssh
+$ chmod 600 ~/.ssh/authorized_keys
+$ chmod 600 ~/.ssh/id_rsa
+$ chmod 600 ~/.ssh/id_rsa.pub
+$ chmod 400 /path/to/access_key.pem
 

网络权限

-
$ chmod -R 644 /var/www/html/
-$ chmod 644 .htaccess
-$ chmod 644 robots.txt
-$ chmod 755 /var/www/uploads/
-$ find /var/www/html -type d -exec chmod 755 {} \;
+
$ chmod -R 644 /var/www/html/
+$ chmod 644 .htaccess
+$ chmod 644 robots.txt
+$ chmod 755 /var/www/uploads/
+$ find /var/www/html -type d -exec chmod 755 {} \;
 

批量更改

-
$ chmod -R 644 /your_path
-$ find /path -type d -exec chmod 755 {} \;
-$ find /path -type f -exec chmod 644 {} \;
+
$ chmod -R 644 /your_path
+$ find /path -type d -exec chmod 755 {} \;
+$ find /path -type f -exec chmod 644 {} \;
 

请参阅:命令替换

另见

diff --git a/docs/cron.html b/docs/cron.html index dcbe6090..3b5f2281 100644 --- a/docs/cron.html +++ b/docs/cron.html @@ -39,17 +39,17 @@

Crontab 格式

格式

-
Min  Hour Day  Mon  Weekday
-分钟  小时  天   月   周
+
Min  Hour Day  Mon  Weekday
+分钟  小时  天   月   周
 

-
*    *    *    *    *  要执行的命令
-┬    ┬    ┬    ┬    ┬
-│    │    │    │    └─  星期几         (0=周日 .. 6=星期六)
-│    │    │    └──────  月            (1..12)
-│    │    └───────────  月份中的某天    (1..31)
-│    └────────────────  小时           (0..23)
-└─────────────────────  分钟           (0..59)
+
*    *    *    *    *  要执行的命令
+┬    ┬    ┬    ┬    ┬
+│    │    │    │    └─  星期几         (0=周日 .. 6=星期六)
+│    │    │    └──────  月            (1..12)
+│    │    └───────────  月份中的某天    (1..31)
+│    └────────────────  小时           (0..23)
+└─────────────────────  分钟           (0..59)
 

diff --git a/docs/docker.html b/docs/docker.html index 43faff98..ed6b11e7 100644 --- a/docs/docker.html +++ b/docs/docker.html @@ -40,7 +40,7 @@

入门

在后台创建和运行容器

-
$ docker run -d -p 80:80 docker/getting-started
+
$ docker run -d -p 80:80 docker/getting-started
 

    @@ -49,7 +49,7 @@
  • docker/getting-started - 要使用的镜像

在前台创建并运行容器

-
$ docker run -it -p 8001:8080 --name my-nginx nginx
+
$ docker run -it -p 8001:8080 --name my-nginx nginx
 

    @@ -211,30 +211,30 @@
    ExampleDescription
    docker ps列出正在运行的容器
    docker ps -a列出所有容器
    docker logs nginx-server容器日志
    docker inspect nginx-server检查容器
    docker events nginx-server容器事件
    docker port nginx-server公共端口
    docker top nginx-server运行进程
    docker stats nginx-server容器资源使用
    docker diff nginx-server列出对容器所做的更改

创建容器

-
docker create [options] IMAGE
-  -a, --attach               # 附加标准输出/错误
-  -i, --interactive          # 附加标准输入(交互式)
-  -t, --tty                  # 伪终端 pseudo-tty
-      --name NAME            # 命名你的镜像
-  -p, --publish 5000:5000    # 端口映射(主机:容器)
-      --expose 5432          # 向容器公开端口 
-  -P, --publish-all          # 发布所有端口
-      --link container:alias # 链接 linking
-  -v, --volume `pwd`:/app    # mount(需要绝对路径)
-  -e, --env NAME=hello       # 环境变量 env vars
+
docker create [options] IMAGE
+  -a, --attach               # 附加标准输出/错误
+  -i, --interactive          # 附加标准输入(交互式)
+  -t, --tty                  # 伪终端 pseudo-tty
+      --name NAME            # 命名你的镜像
+  -p, --publish 5000:5000    # 端口映射(主机:容器)
+      --expose 5432          # 向容器公开端口 
+  -P, --publish-all          # 发布所有端口
+      --link container:alias # 链接 linking
+  -v, --volume `pwd`:/app    # mount(需要绝对路径)
+  -e, --env NAME=hello       # 环境变量 env vars
 

实例

-
$ docker create --name my_redis --expose 6379 redis:3.0.2
+
$ docker create --name my_redis --expose 6379 redis:3.0.2
 

操控

重命名容器

-
docker rename my-nginx nginx-server
+
docker rename my-nginx nginx-server
 

移除容器

-
docker rm nginx-server
+
docker rm nginx-server
 

更新容器

-
docker update --cpu-shares 512 -m 300M nginx-server
+
docker update --cpu-shares 512 -m 300M nginx-server
 

Docker 镜像

@@ -286,49 +286,49 @@
ExampleDescription
docker images列出镜像
docker rmi nginx删除镜像
docker load < ubuntu.tar.gz加载一个 tarred 存储库
docker load --input ubuntu.tar加载一个 tarred 存储库
docker save busybox > ubuntu.tar将镜像保存到 tar 存档
docker history显示镜像的历史
docker commit nginx将容器另存为镜像。
docker tag nginx eon01/nginx标记镜像
docker push eon01/nginx推送镜像

构建镜像

-
$ docker build .
-$ docker build github.com/creack/docker-firefox
-$ docker build - < Dockerfile
-$ docker build - < context.tar.gz
-$ docker build -t eon/nginx-server .
-$ docker build -f myOtherDockerfile .
-$ curl example.com/remote/Dockerfile | docker build -f - .
+
$ docker build .
+$ docker build github.com/creack/docker-firefox
+$ docker build - < Dockerfile
+$ docker build - < context.tar.gz
+$ docker build -t eon/nginx-server .
+$ docker build -f myOtherDockerfile .
+$ curl example.com/remote/Dockerfile | docker build -f - .
 

Docker 网络

操作

删除网络

-
docker network rm MyOverlayNetwork
+
docker network rm MyOverlayNetwork
 

列出网络

-
docker network ls
+
docker network ls
 

获取有关网络的信息

-
docker network inspect MyOverlayNetwork
+
docker network inspect MyOverlayNetwork
 

将正在运行的容器连接到网络

-
docker network connect MyOverlayNetwork nginx
+
docker network connect MyOverlayNetwork nginx
 

启动时将容器连接到网络

-
docker run -it -d --network=MyOverlayNetwork nginx
+
docker run -it -d --network=MyOverlayNetwork nginx
 

断开容器与网络的连接

-
docker network disconnect MyOverlayNetwork nginx
+
docker network disconnect MyOverlayNetwork nginx
 

创建网络

-
docker network create -d overlay MyOverlayNetwork
-docker network create -d bridge MyBridgeNetwork
-docker network create -d overlay \
-  --subnet=192.168.0.0/16 \
-  --subnet=192.170.0.0/16 \
-  --gateway=192.168.0.100 \
-  --gateway=192.170.0.100 \
-  --ip-range=192.168.1.0/24 \
-  --aux-address="my-router=192.168.1.5" \
-  --aux-address="my-switch=192.168.1.6" \
-  --aux-address="my-printer=192.170.1.5" \
-  --aux-address="my-nas=192.170.1.6" \
-  MyOverlayNetwork
+
docker network create -d overlay MyOverlayNetwork
+docker network create -d bridge MyBridgeNetwork
+docker network create -d overlay \
+  --subnet=192.168.0.0/16 \
+  --subnet=192.170.0.0/16 \
+  --gateway=192.168.0.100 \
+  --gateway=192.170.0.100 \
+  --ip-range=192.168.1.0/24 \
+  --aux-address="my-router=192.168.1.5" \
+  --aux-address="my-switch=192.168.1.6" \
+  --aux-address="my-printer=192.170.1.5" \
+  --aux-address="my-nas=192.170.1.6" \
+  MyOverlayNetwork
 

各种各样的

@@ -362,24 +362,24 @@

注册表命令

登录到注册表

-
$ docker login
-$ docker login localhost:8080
+
$ docker login
+$ docker login localhost:8080
 

从注册表注销

-
$ docker logout
-$ docker logout localhost:8080
+
$ docker logout
+$ docker logout localhost:8080
 

搜索镜像

-
$ docker search nginx
-$ docker search nginx --stars=3 --no-trunc busybox
+
$ docker search nginx
+$ docker search nginx --stars=3 --no-trunc busybox
 

拉取镜像

-
$ docker pull nginx
-$ docker pull eon01/nginx localhost:5000/myadmin/nginx
+
$ docker pull nginx
+$ docker pull eon01/nginx localhost:5000/myadmin/nginx
 

推送镜像

-
$ docker push eon01/nginx
-$ docker push eon01/nginx localhost:5000/myadmin/nginx
+
$ docker push eon01/nginx
+$ docker push eon01/nginx localhost:5000/myadmin/nginx
 

批量清除

@@ -406,10 +406,10 @@
实例说明
docker stop -f $(docker ps -a -q)停止所有容器
docker rm -f $(docker ps -a -q)删除所有容器
docker rmi -f $(docker images -q)删除所有图像

卷 volume

检查卷

-
$ docker volume ls
+
$ docker volume ls
 

清理未使用的卷

-
$ docker volume prune
+
$ docker volume prune
 

另见

    diff --git a/docs/dockerfile.html b/docs/dockerfile.html index 346c1e6d..92af7cb2 100644 --- a/docs/dockerfile.html +++ b/docs/dockerfile.html @@ -42,58 +42,58 @@ -
    docker build -f /path/to/a/Dockerfile .
    +
    docker build -f /path/to/a/Dockerfile .
     

    使用 -f 指向文件系统中任何位置的 Dockerfile

继承

-
FROM [--platform=<platform>] <image> [AS <name>]
+
FROM [--platform=<platform>] <image> [AS <name>]
 

示例

-
FROM ruby:2.2.2
-FROM golang:1.19-alpine3.16 AS build-env
+
FROM ruby:2.2.2
+FROM golang:1.19-alpine3.16 AS build-env
 

变量 ENV

-
ENV <key>=<value> ...
+
ENV <key>=<value> ...
 
-
ENV APP_HOME /myapp
-RUN mkdir $APP_HOME
+
ENV APP_HOME /myapp
+RUN mkdir $APP_HOME
 
-
ENV MY_NAME="John Doe" MY_DOG=Rex\ The\ Dog \
-    MY_CAT=fluffy
+
ENV MY_NAME="John Doe" MY_DOG=Rex\ The\ Dog \
+    MY_CAT=fluffy
 

初始化

-
RUN bundle install
+
RUN bundle install
 

WORKDIR 指令为任何 RUNCMDENTRYPOINTCOPYADD 指令设置工作目录。

-
WORKDIR /myapp
+
WORKDIR /myapp
 

VOLUME 指令创建一个具有指定名称的挂载点,并将其标记为保存来自本机主机或其他容器的外部挂载卷。

-
VOLUME ["/data"]
-# 安装点规范
+
VOLUME ["/data"]
+# 安装点规范
 
-
ADD file.xyz /file.xyz
-# 复制
-COPY --chown=user:group host_file.xyz /path/container_file.xyz
+
ADD file.xyz /file.xyz
+# 复制
+COPY --chown=user:group host_file.xyz /path/container_file.xyz
 

Onbuild

-
ONBUILD RUN bundle install
-# 与另一个文件一起使用时
-
-ONBUILD ADD . /app/src
-ONBUILD RUN /usr/local/bin/python-build --dir /app/src
+
ONBUILD RUN bundle install
+# 与另一个文件一起使用时
+
+ONBUILD ADD . /app/src
+ONBUILD RUN /usr/local/bin/python-build --dir /app/src
 

指令将触发指令添加到镜像中,以便稍后执行,此时镜像用作另一个构建的基础。

在严格的 shell 中运行命令

-
ENV my_var
-SHELL ["/bin/bash", "-euo", "pipefail", "-c"]
-# 使用严格模式:
-RUN false         # ails 像使用 && 一样构建
-RUN echo "$myvar" # 由于拼写错误会抛出错误
-RUN true | false  # 将脱离管道
+
ENV my_var
+SHELL ["/bin/bash", "-euo", "pipefail", "-c"]
+# 使用严格模式:
+RUN false         # ails 像使用 && 一样构建
+RUN echo "$myvar" # 由于拼写错误会抛出错误
+RUN true | false  # 将脱离管道
 

使用 shell 将为 shell 命令打开严格模式。

@@ -121,46 +121,46 @@
:--
CMD ["executable","param1","param2"](exec 形式,这是首选形式)
CMD ["param1","param2"](作为 ENTRYPOINT 的默认参数)
CMD command param1 param2(shell形式)
-
EXPOSE 5900
-CMD ["bundle", "exec", "rails", "server"]
+
EXPOSE 5900
+CMD ["bundle", "exec", "rails", "server"]
 

入口点 ENTRYPOINT

-
ENTRYPOINT ["executable", "param1", "param2"]
-ENTRYPOINT command param1 param2
+
ENTRYPOINT ["executable", "param1", "param2"]
+ENTRYPOINT command param1 param2
 

配置将作为可执行文件运行的容器。

-
ENTRYPOINT exec top -b
+
ENTRYPOINT exec top -b
 

这将使用 shell 处理来替换 shell 变量,并将忽略任何 CMDdocker run 命令行参数。

元数据 LABEL

-
LABEL version="1.0"
+
LABEL version="1.0"
 
-
LABEL "com.example.vendor"="ACME Incorporated"
-LABEL com.example.label-with-value="foo"
-LABEL version="1.0"
+
LABEL "com.example.vendor"="ACME Incorporated"
+LABEL com.example.label-with-value="foo"
+LABEL version="1.0"
 
-
LABEL description="本文说明\
-标签值可以跨越多行。"
-LABEL multi.label1="value1" \
-      multi.label2="value2" \
-      other="value3"
+
LABEL description="本文说明\
+标签值可以跨越多行。"
+LABEL multi.label1="value1" \
+      multi.label2="value2" \
+      other="value3"
 

ARG

-
ARG <name>[=<default value>]
+
ARG <name>[=<default value>]
 

指令定义了一个变量,在构建时通过 docker build 命令使用 --build-arg <varname>=<value> 标志将其传递给构建器。

-
FROM busybox
-# user1 默认值为 someuser
-ARG user1=someuser
-ARG buildno=1
+
FROM busybox
+# user1 默认值为 someuser
+ARG user1=someuser
+ARG buildno=1
 

.dockerignore 文件

-
# 注释说明
-*/temp*
-*/*/temp*
-temp?
+
# 注释说明
+*/temp*
+*/*/temp*
+temp?
 

@@ -244,16 +244,16 @@
命令说明
FROM image构建的基础镜像
MAINTAINER email(已弃用)维护者的名字
COPY [--chown=<user>:<group>] <src>... <dest>将上下文中的路径复制到位置 dest 的容器中
ADD [--chown=<user>:<group>] <src>... <dest>COPY 相同,但解压缩存档并接受 http url。
RUN <command>在容器内运行任意命令。
USER <user>[:<group>]设置默认用户名。
WORKDIR /path/to/workdir设置默认工作目录。
CMD command param1 param2设置默认命令
ENV <key>=<value> ...设置环境变量
EXPOSE <port> [<port>/<protocol>...]运行时侦听指定的网络端口

服务静态网站的最小 Docker 镜像

-
FROM lipanski/docker-static-website:latest
-# 使用 .dockerignore 文件来控制图像中的内容!
-# 复制当前目录内容,到容器中
-COPY ./ .
+
FROM lipanski/docker-static-website:latest
+# 使用 .dockerignore 文件来控制图像中的内容!
+# 复制当前目录内容,到容器中
+COPY ./ .
 

这会产生一个 154KB + 的单层镜像。 如果您需要以不同的方式配置 httpd,您可以覆盖 CMD 行:

-
FROM lipanski/docker-static-website:latest
-COPY . .
-
-CMD ["/busybox", "httpd", "-f", "-v", "-p", "3000", "-c", "httpd.conf"]
+
FROM lipanski/docker-static-website:latest
+COPY . .
+
+CMD ["/busybox", "httpd", "-f", "-v", "-p", "3000", "-c", "httpd.conf"]
 

缩小镜像过程查看原文,镜像 Dockerfile 源码

也可以看看

diff --git a/docs/find.html b/docs/find.html index 1338b681..3fb4c734 100644 --- a/docs/find.html +++ b/docs/find.html @@ -38,12 +38,12 @@

这是 Linux find 命令备忘单的快速参考列表,包含常用选项和示例。

入门

用法

-
$ find [path...] [options] [expression]
+
$ find [path...] [options] [expression]
 

通配符

-
$ find . -name "*.txt"
-$ find . -name "2020*.csv"
-$ find . -name "json_*"
+
$ find . -name "*.txt"
+$ find . -name "2020*.csv"
+$ find . -name "json_*"
 

    @@ -183,84 +183,84 @@
    -size b512 字节块(默认)
    -size c字节
    -size k千字节
    -size M兆字节
    -size G千兆字节
    -size T太字节_(仅限 BSD)_
    -size PPB (仅 BSD)

大小 +/-

查找所有大于 10MB 的文件

-
$ find / -size +10M
+
$ find / -size +10M
 

查找所有小于 10MB 的文件

-
$ find / -size -10M
+
$ find / -size -10M
 

查找所有正好为 10M 的文件

-
$ find / -size 10M
+
$ find / -size 10M
 

查找 100MB 和 1GB 之间的大小

-
$ find / -size +100M -size -1G
+
$ find / -size +100M -size -1G
 

像往常一样,+- 前缀表示大于和小于。

名称

在当前目录中使用名称查找文件

-
$ find . -name tecmint.txt
+
$ find . -name tecmint.txt
 

查找主目录下的文件

-
$ find /home -name tecmint.txt
+
$ find /home -name tecmint.txt
 

使用名称查找文件并忽略大小写

-
$ find /home -iname tecmint.txt
+
$ find /home -iname tecmint.txt
 

使用名称查找目录

-
$ find / -type d -name tecmint
+
$ find / -type d -name tecmint
 

使用名称查找php文件

-
$ find . -type f -name tecmint.php
+
$ find . -type f -name tecmint.php
 

查找目录下的所有php文件

-
$ find . -type f -name "*.php"
+
$ find . -type f -name "*.php"
 

权限

查找权限为 777 的文件。

-
$ find . -type f -perm 0777 -print
+
$ find . -type f -perm 0777 -print
 

查找未经许可的文件 777.

-
$ find / -type f ! -perm 777
+
$ find / -type f ! -perm 777
 

查找 SUID 集文件。

-
$ find / -perm /u=s
+
$ find / -perm /u=s
 

查找 SGID 集文件。

-
$ find / -perm /g=s
+
$ find / -perm /g=s
 

查找只读文件。

-
$ find / -perm /u=r
+
$ find / -perm /u=r
 

查找可执行文件。

-
$ find / -perm /a=x
+
$ find / -perm /a=x
 

所有者和组

根据用户查找单个文件

-
$ find / -user root -name tecmint.txt
+
$ find / -user root -name tecmint.txt
 

根据用户查找所有文件

-
$ find /home -user tecmint
+
$ find /home -user tecmint
 

根据组查找所有文件

-
$ find /home -group developer
+
$ find /home -group developer
 

查找用户的特定文件

-
$ find /home -user tecmint -iname "*.txt"
+
$ find /home -user tecmint -iname "*.txt"
 

多个文件名

-
$ find . -type f \( -name "*.sh" -o -name "*.txt" \)
+
$ find . -type f \( -name "*.sh" -o -name "*.txt" \)
 

查找带有 .sh.txt 扩展名的文件

多个目录

-
$ find /opt /usr /var -name foo.scala -type f
+
$ find /opt /usr /var -name foo.scala -type f
 

查找具有多个目录的文件

空的

-
$ find . -type d -empty
+
$ find . -type d -empty
 

删除目录中的所有空文件

-
$ find . -type f -empty -delete
+
$ find . -type f -empty -delete
 

查找日期和时间

方法

@@ -348,75 +348,75 @@
OptionDescription
-mtime +024 小时前修改
-mtime 0从现在到 1 天前修改
-mtime -1不到 1 天前修改(与 -mtime 0 相同)
-mtime 124 至 48 小时前修改
-mtime +1超过 48 小时前修改
-mtime +1w上次修改时间超过 1 周前
-atime 0从现在到 24 小时前最后一次访问
-atime +0访问时间超过 24 小时
-atime 1在 24 至 48 小时前访问
-atime +1访问时间超过 48 小时
-atime -1不到 24 小时前访问过(与 -atime 0 相同)
-ctime -6h30m文件状态在过去 6 小时 30 分钟内发生变化

更多示例

查找最近 50 天修改的文件

-
$ find / -mtime 50
+
$ find / -mtime 50
 

查找最近 50 天访问的文件

-
$ find / -atime 50
+
$ find / -atime 50
 

查找最近 50-100 天修改的文件

-
$ find / -mtime +50 –mtime -100
+
$ find / -mtime +50 –mtime -100
 

查找最近 1 小时内更改的文件

-
$ find / -cmin -60
+
$ find / -cmin -60
 

查找最近 1 小时内修改过的文件

-
$ find / -mmin -60
+
$ find / -mmin -60
 

查找最近 1 小时内访问过的文件

-
$ find / -amin -60
+
$ find / -amin -60
 

查找并

查找和删除

查找并删除多个文件

-
$ find . -type f -name "*.mp3" -exec rm -f {} \;
+
$ find . -type f -name "*.mp3" -exec rm -f {} \;
 

查找和删除单个文件

-
$ find . -type f -name "tecmint.txt" -exec rm -f {} \;
+
$ find . -type f -name "tecmint.txt" -exec rm -f {} \;
 

查找和删除 100mb 文件

-
$ find / -type f -size +100m -exec rm -f {} \;
+
$ find / -type f -size +100m -exec rm -f {} \;
 

查找特定文件并删除

-
$ find / -type f -name *.mp3 -size +10m -exec rm {} \;
+
$ find / -type f -name *.mp3 -size +10m -exec rm {} \;
 

查找和替换

-
$ find ./ -type f -exec sed -i 's/find/replace/g' {} \;
-$ find ./ -type f -readable -writable -exec sed -i "s/old/new/g" {} \;
+
$ find ./ -type f -exec sed -i 's/find/replace/g' {} \;
+$ find ./ -type f -readable -writable -exec sed -i "s/old/new/g" {} \;
 

参见:sed 命令

查找和重命名

-
$ find . -type f -name 'file*' -exec mv {} {}_renamed \;
-$ find . -type f -name 'file*' -exec sh -c 'x="{}"; mv "$x" "${x}.bak"' \;
+
$ find . -type f -name 'file*' -exec mv {} {}_renamed \;
+$ find . -type f -name 'file*' -exec sh -c 'x="{}"; mv "$x" "${x}.bak"' \;
 

查找和移动

-
$ find . -name '*.mp3' -exec mv {} /tmp/music \;
+
$ find . -name '*.mp3' -exec mv {} /tmp/music \;
 

查找并将其移动到特定目录

查找和复制

-
$ find . -name '*2020*.xml' -exec cp -r "{}" /tmp/backup \;
+
$ find . -name '*2020*.xml' -exec cp -r "{}" /tmp/backup \;
 

查找并将其复制到特定目录

查找并连接

-
$ find download -type f -iname '*.csv' | xargs cat > merged.csv
-$ find download -type f -name '*.gz' -exec cat {} \; > output
+
$ find download -type f -iname '*.csv' | xargs cat > merged.csv
+$ find download -type f -name '*.gz' -exec cat {} \; > output
 

查找和排序

-
$ find . -printf "%T+\t%p\n" | sort
-$ find . -printf "%T+\t%p\n" | sort -r
+
$ find . -printf "%T+\t%p\n" | sort
+$ find . -printf "%T+\t%p\n" | sort -r
 

查找和 chmod

查找文件并将权限设置为 644。

-
$ find / -type f -perm 0777 -print -exec chmod 644 {} \;
+
$ find / -type f -perm 0777 -print -exec chmod 644 {} \;
 

查找目录并将权限设置为 755。

-
$ find / -type d -perm 777 -print -exec chmod 755 {} \;
+
$ find / -type d -perm 777 -print -exec chmod 755 {} \;
 

查找并 tar

-
$ find . -type f -name "*.java" | xargs tar cvf myfile.tar
-$ find . -type f -name "*.java" | xargs tar rvf myfile.tar
+
$ find . -type f -name "*.java" | xargs tar cvf myfile.tar
+$ find . -type f -name "*.java" | xargs tar rvf myfile.tar
 
© 2022 Kenny Wang, All rights reserved.
diff --git a/docs/git.html b/docs/git.html index 19c9a05d..ab081e0c 100644 --- a/docs/git.html +++ b/docs/git.html @@ -39,302 +39,302 @@

入门

创建存储库

创建一个新的本地存储库

-
$ git init [project name]
+
$ git init [project name]
 

克隆存储库

-
$ git clone git_url
+
$ git clone git_url
 

将存储库克隆到指定目录

-
$ git clone git_url 指定目录
+
$ git clone git_url 指定目录
 

做出改变

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

-
$ git status
+
$ git status
 

暂存文件,准备提交

-
$ git add [file]
+
$ git add [file]
 

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

-
$ git add .
+
$ git add .
 

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

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

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

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

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

-
$ git reset [file]
+
$ git reset [file]
 

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

-
$ git reset --hard
+
$ git reset --hard
 

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

-
$ git diff
+
$ git diff
 

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

-
$ git diff --staged
+
$ git diff --staged
 

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

-
$ git rebase [branch]
+
$ git rebase [branch]
 

配置

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

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

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

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

启用 Git 输出的一些着色

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

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

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

使用分支

列出所有本地分支

-
$ git branch
+
$ git branch
 

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

-
$ git branch -av
+
$ git branch -av
 

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

-
$ git checkout my_branch
+
$ git checkout my_branch
 

创建一个名为 new_branch 的新分支

-
$ git checkout -b new_branch
+
$ git checkout -b new_branch
 

删除名为 my_branch 的分支

-
$ git branch -d my_branch
+
$ git branch -d my_branch
 

将分支 A 合并到分支 B

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

标记当前提交

-
$ git tag my_tag
+
$ git tag my_tag
 

观察你的存储库

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

-
$ git log
+
$ git log
 

显示 branchA 上不在 branchB 上的提交

-
$ git log branchB..branchA
+
$ git log branchB..branchA
 

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

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

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

-
$ git diff branchB...branchA
+
$ git diff branchB...branchA
 

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

-
$ git show [SHA]
+
$ git show [SHA]
 

同步

从该 Git 远程获取所有分支

-
$ git fetch [alias]
+
$ git fetch [alias]
 

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

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

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

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

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

-
$ git pull
+
$ git pull
 

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

-
$ git cherry-pick [commit_id]
+
$ git cherry-pick [commit_id]
 

远程

添加一个 git URL 作为别名

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

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

-
$ git remote
+
$ git remote
 

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

-
$ git remote -v
+
$ git remote -v
 

删除远程存储库

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

更改 git repo 的 URL

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

临时提交

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

-
$ git stash
+
$ git stash
 

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

-
$ git stash list
+
$ git stash list
 

从存储堆栈顶部编写工作

-
$ git stash pop
+
$ git stash pop
 

丢弃存储堆栈顶部的更改

-
$ git stash drop
+
$ git stash drop
 

跟踪路径更改

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

-
$ git rm [file]
+
$ git rm [file]
 

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

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

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

-
$ git log --stat -M
+
$ git log --stat -M
 

忽略文件

-
/logs/*
-# “!” 意思是不要忽视
-!logs/.gitkeep
-# 忽略 Mac 系统文件
-.DS_store
-# 忽略 node_modules 文件夹
-node_modules
-# 忽略 SASS 配置文件
-.sass-cache
+
/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 branch -m <new>
+$ git branch -m <old> <new> # 重命名分支  
 

推送并重置

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

删除远程分支

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

Log

按内容搜索更改

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

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

-
$ git log -p <file_name>
+
$ git log -p <file_name>
 

打印出很酷的日志可视化

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

分支

列出所有分支及其上游

-
$ git branch -vv 
+
$ git branch -vv 
 

快速切换到上一个分支

-
$ git checkout -
+
$ git checkout -
 

只获取远程分支

-
$ git branch -r
+
$ git branch -r
 

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

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

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

-
git remote prune origin
+
git remote prune origin
 

Commit

-
$ git commit -v --amend
+
$ git commit -v --amend
 

重写最后的提交信息

忽略文件的权限变化

-
git config core.fileMode false
+
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
+
$ 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 <目录/文件> 
+
# 查看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 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 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 HEAD~1
+# 强制同步到远程仓库  
+$ git push -f origin HEAD:master
 

放弃本地修改内容

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

获取最近一次提交的 Hash

-
$ git rev-parse HEAD # e10721cb8859b2c
-# 获取短 hash
-$ git rev-parse --short HEAD # e10721c
+
$ 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 branch --merged master | grep -v '^\*\|  master' | xargs -n 1 git branch -d
 

中文乱码的解决方案

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

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

-
# 切换到 B 分支
-$ git checkout <B>
-# 将 A 分支 <hash-id> 的内容 pick 到 B 分支
-$ git cherry-pick <hash-id>
+
# 切换到 B 分支
+$ git checkout <B>
+# 将 A 分支 <hash-id> 的内容 pick 到 B 分支
+$ git cherry-pick <hash-id>
 
diff --git a/docs/javascript.html b/docs/javascript.html index 15b73d18..29c6c970 100644 --- a/docs/javascript.html +++ b/docs/javascript.html @@ -45,440 +45,440 @@
  • TypeScript 备忘清单
  • 打印调试

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

    断点调试

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

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

    数字

    -
    let amount = 6;
    -let price = 4.99;
    -let home = 1e2;
    -let m = 0644;   // 八进制数字 420
    +
    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
    +
    let count; 
    +console.log(count); // => undefined
    +count = 10;
    +console.log(count); // => 10
     

    const 关键字

    -
    const numberOfColumns = 4;
    -// TypeError: Assignment to constant...
    -numberOfColumns = 8;
    +
    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 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);
    +
    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
    +
    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 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.`;
    +
    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 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    
    +
    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;  
    +
    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();                 
    +
    // 像脚本代码一样执行字符串
    +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 || 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
    +
    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
    +
    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); 
    +
    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'          //  ''
    +
    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');
    -}
    +
    const isMailSent = true;
    +if (isMailSent) {
    +  console.log('Mail sent to recipient');
    +}
     

    Ternary Operator (三元运算符)

    -
    var age = 1;
    -
    -// => true
    -var status = (age >= 18) ? true : false;
    +
    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
    +
    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
    +
    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('请您用餐');
    -}
    +
    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('请您用餐');
    -}
    +
    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
    +
    // 定义函数:
    +function sum(num1, num2) {
    +  return num1 + num2;
    +}
    +// 调用函数:
    +sum(3, 6); // 9
     

    匿名函数

    -
    // Named function
    -function rocketToMars() {
    -  return 'BOOM!';
    -}
    -// Anonymous function
    -const rocketToMars = function() {
    -  return 'BOOM!';
    -}
    +
    // 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 sum = (param1, param2) => { 
    +  return param1 + param2; 
    +}; 
    +console.log(sum(2,5)); // => 7 
     

    没有参数

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

    只有一个参数

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

    简洁箭头函数

    -
    const multiply = (a, b) => a * b; 
    -// => 60 
    -console.log(multiply(2, 30)); 
    +
    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;
    -}
    +
    // 有 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
    +
    // 定义函数
    +function sum(num1, num2) {
    +  return num1 + num2;
    +}
    +// 调用函数
    +sum(2, 4); // 6
     

    函数表达式

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

    函数参数

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

    函数声明

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

    JavaScript 范围

    范围

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

    { } 块内声明的变量

    -
    {
    -  let x = 2;
    -}
    -// ❌ x 不能在这里使用
    -
    -{
    -  var x = 2;
    -}
    -// ✅ x 能在这里使用
    +
    {
    +  let x = 2;
    +}
    +// ❌ x 不能在这里使用
    +
    +{
    +  var x = 2;
    +}
    +// ✅ x 能在这里使用
     
    -
    var x = 2;       // Global scope
    -let x = 2;       // Global scope
    -const x = 2;       // Global scope
    +
    var x = 2;       // Global scope
    +let x = 2;       // Global scope
    +const x = 2;       // Global scope
     

    ES6 引入了两个重要的新 JavaScript 关键字:let 和 const。这两个关键字在 JavaScript 中提供了块作用域。

    块作用域变量

    -
    const isLoggedIn = true;
    -if (isLoggedIn == true) {
    -  const statusMessage = 'Logged in.';
    -}
    -// Uncaught ReferenceError...
    -// 未捕获的引用错误...
    -console.log(statusMessage);
    +
    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
    +
    // 全局声明的变量
    +const color = 'blue';
    +function printColor() {
    +  console.log(color);
    +}
    +
    +printColor(); // => blue
     

    let vs var

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

    -
    for (var i = 0; i < 3; i++) {
    -  // 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);
    -}
    +
    // 打印三次,不是我们的意思。
    +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);
    -}
    +
    // 按预期打印 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];
    +
    const fruits = ["apple", "dew", "banana"];
    +// 不同的数据类型
    +const data = [1, 'chicken', false];
     

    属性 .length

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

    索引

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

    可变图表

    @@ -524,835 +524,835 @@
    添加删除开始结束
    push
    pop
    unshift
    shift

    方法 .push()

    -
    // 添加单个元素:
    -const cart = ['apple', 'orange'];
    -cart.push('pear'); 
    -// 添加多个元素:
    -const numbers = [1, 2];
    -numbers.push(3, 4, 5);
    +
    // 添加单个元素:
    +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"]
    +
    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']
    +
    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');
    +
    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)
    +
    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++;
    -}
    +
    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
    +
    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
    +
    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 < 4; i += 1) {
    +  console.log(i);
    +};
    +// => 0, 1, 2, 3
     

    遍历数组

    -
    for (let i = 0; i < array.length; i++){
    -  console.log(array[i]);
    -}
    -// => 数组中的每一项
    +
    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
    +
    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 (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 (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
    +
    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
    +
    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
    +
    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
    +
    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++;
    -}
    +
    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
    +
    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.
    +
    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
    +
    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);
    +
    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);
    -}); 
    +
    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;
    -});
    +
    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 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 trainSchedule = {
    +  // 由于单词之间的空格而无效。
    +  platform num: 10, 
    +  // 表达式不能是键。
    +  40 - 10 + 2: 30,
    +  // 除非用引号括起来,否则 + 号无效。
    +  +compartment: 'C'
    +}
     

    不存在的属性

    -
    const classElection = {
    -  date: 'January 12'
    -};
    -console.log(classElection.place); // undefined
    +
    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 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 = {
    +  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 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);
    +
    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!');  
    -    }
    -  };
    -};
    +
    // 一个接受 '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' }
    +
    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 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();
    +
    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';
    +
    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 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 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();
    +
    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
    -});
    +
    // 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 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!');
    -  }
    -}
    +
    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
    -}
    +
    // 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>
    +
    // 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
    -}
    +
    // 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
    +
    // 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

    创建 promises

    -
    new Promise((resolve, reject) => {
    -  if (ok) {
    -    resolve(result)
    -  } else {
    -    reject(error)
    -  }
    -})
    +
    new Promise((resolve, reject) => {
    +  if (ok) {
    +    resolve(result)
    +  } else {
    +    reject(error)
    +  }
    +})
     

    使用 promises

    -
    promise
    -  .then((result) => { ··· })
    -  .catch((error) => { ··· })
    +
    promise
    +  .then((result) => { ··· })
    +  .catch((error) => { ··· })
     

    Promise 方法

    -
    Promise.all(···)
    -Promise.race(···)
    -Promise.reject(···)
    -Promise.resolve(···)
    +
    Promise.all(···)
    +Promise.race(···)
    +Promise.reject(···)
    +Promise.resolve(···)
     

    执行器函数

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

    setTimeout()

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

    Promise 状态

    -
    const promise = new Promise((resolve, reject) => {
    -  const res = true;
    -  // 一个异步操作。
    -  if (res) {
    -    resolve('Resolved!');
    -  }
    -  else {
    -    reject(Error('Error'));
    -  }
    -});
    -promise.then(
    -  (res) => console.log(res),
    -  (err) => console.error(err)
    -);
    +
    const promise = new Promise((resolve, reject) => {
    +  const res = true;
    +  // 一个异步操作。
    +  if (res) {
    +    resolve('Resolved!');
    +  }
    +  else {
    +    reject(Error('Error'));
    +  }
    +});
    +promise.then(
    +  (res) => console.log(res),
    +  (err) => console.error(err)
    +);
     

    .then() 方法

    -
    const promise = new Promise((resolve, reject) => {    
    -  setTimeout(() => {
    -    resolve('Result');
    -  }, 200);
    -});
    -
    -promise.then((res) => {
    -  console.log(res);
    -}, (err) => {
    -  console.error(err);
    -});
    +
    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 无条件拒绝。'));
    -  }, 1000);
    -});
    -
    -promise.then((res) => {
    -  console.log(value);
    -});
    -
    -promise.catch((err) => {
    -  console.error(err);
    -});
    +
    const promise = new Promise(
    +  (resolve, reject) => {  
    +  setTimeout(() => {
    +    reject(Error('Promise 无条件拒绝。'));
    +  }, 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]);
    -});
    +
    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]);
    +});
     

    链接多个 .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)
    -});
    +
    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)
    +});
     

    避免嵌套的 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 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);
     

    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 秒后
    +
    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"]
    +
    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 秒后
    +
    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!" );
    -}
    +
    // 数据不完整
    +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 秒后
    +
    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  
    -};
    +
    const jsonObj = {
    +  "name": "Rick",
    +  "id": "11A",
    +  "level": 4  
    +};
     

    另见:JSON 备忘单

    XMLHttpRequest

    -
    const xhr = new XMLHttpRequest();
    -xhr.open('GET', 'mysite.com/getjson');
    +
    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();
    +
    const req = new XMLHttpRequest();
    +req.responseType = 'json';
    +req.open('GET', '/getdata?id=65');
    +req.onload = () => {
    +  console.log(xhr.response);
    +};
    +req.send();
     

    POST

    -
    const data = { weight: '1.5 KG' };
    -const xhr = new XMLHttpRequest();
    -// 初始化一个请求。
    -xhr.open('POST', '/inventory/add');
    -// 一个用于定义响应类型的枚举值
    -xhr.responseType = 'json';
    -// 发送请求以及数据。
    -xhr.send(JSON.stringify(data));
    -// 请求成功完成时触发。
    -xhr.onload = () => {
    -  console.log(xhr.response);
    -}
    -// 当 request 遭遇错误时触发。
    -xhr.onerror = () => {
    -  console.log(xhr.response);
    -}
    +
    const data = { weight: '1.5 KG' };
    +const xhr = new XMLHttpRequest();
    +// 初始化一个请求。
    +xhr.open('POST', '/inventory/add');
    +// 一个用于定义响应类型的枚举值
    +xhr.responseType = 'json';
    +// 发送请求以及数据。
    +xhr.send(JSON.stringify(data));
    +// 请求成功完成时触发。
    +xhr.onload = () => {
    +  console.log(xhr.response);
    +}
    +// 当 request 遭遇错误时触发。
    +xhr.onerror = () => {
    +  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)
    -})
    +
    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);
    -  });
    +
    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('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);
    -})
    +
    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)
    -  }
    -}
    +
    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)
    +  }
    +}
     
    © 2022 Kenny Wang, All rights reserved.
    diff --git a/docs/jest.html b/docs/jest.html index 077c822c..f49fc414 100644 --- a/docs/jest.html +++ b/docs/jest.html @@ -48,142 +48,142 @@

    测试结构

    -
    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'])
    -  })
    -})
    +
    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 })
    +
    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))
    +
    // 匹配 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(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('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([]).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(),
    -])
    +
    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)
    +
    // 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)
     

    别名

      @@ -197,78 +197,78 @@
    • nthReturnedWithtoHaveNthReturnedWith

    杂项

    -
    // 检查对象是否是类的实例。
    -expect(new A()).toBeInstanceOf(A)
    -
    -// 检查对象是否是函数的实例。
    -expect(() => {}).toEqual(
    -  expect.any(Function)
    -)
    -
    -// 匹配除 null 或 undefined 之外的任何内容
    -expect('pizza').toEqual(expect.anything())
    +
    // 检查对象是否是类的实例。
    +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()
    +
    // 这可确保某个值与最近的快照匹配。
    +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()
    -})
    +
    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')
    -})
    +
    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()
    +
    // 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()
     

    别名

      @@ -279,113 +279,113 @@

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

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

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

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

      -
      beforeEach(expect.hasAssertions)
      +
      beforeEach(expect.hasAssertions)
       

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

    async/await

    -
    test('async test', async () => {
    -  expect.assertions(1)
    -
    -  const result = await runAsyncOperation()
    -  expect(result).toBe(true)
    -})
    +
    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)
    -    }
    -  })
    -})
    +
    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)
    -  })
    -})
    +
    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', () => {
    +  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 [
    -  // ...
    -})
    +
    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(() => true)
     

    模拟函数文档

    返回、解析和拒绝值

    您的模拟可以返回值:

    -
    const callback
    -    = jest.fn().mockReturnValue(true)
    -const callbackOnce
    -    = jest.fn().mockReturnValueOnce(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 promise 
    +    = jest.fn().mockResolvedValue(true)
    +const promiseOnce 
    +    = jest.fn().mockResolvedValueOnce(true)
     

    他们甚至可以拒绝值:

    -
    const failedPromise
    -    = jest.fn().mockRejectedValue('Error')
    -const failedPromiseOnce
    -    = jest.fn().mockRejectedValueOnce('Error')
    +
    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
    +
    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('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

    @@ -393,157 +393,157 @@

    使用模拟文件模拟模块

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

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

    添加到您的测试中:

    -
    jest.mock('lodash/memoize')
    +
    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(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()
    +
    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(() => {})
    +
    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)
    -})
    +
    // 启用假计时器
    +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.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,
    -})
    +
    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()
    +
    // 清除模拟使用日期
    +// (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()
    +
    // 清除所有 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.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([
    +  [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)
    -})
    +
    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([
    +  ['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.skip('makePoniesPink'...
    +tests.skip('make each pony pink'...
     

    仅运行以下测试

    -
    describe.only('makePoniesPink'...
    -tests.only('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()
    -})
    +
    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.jsJest 会缓存你需要的模块。 要测试具有副作用的模块,您需要在测试之间重置模块注册表

    另见

    diff --git a/docs/json.html b/docs/json.html index 58674919..dc417eb0 100644 --- a/docs/json.html +++ b/docs/json.html @@ -47,18 +47,18 @@
  • 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"}
    -  ]
    -}
    +
    {
    +  "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"}
    +  ]
    +}
     

    类型

    @@ -148,14 +148,14 @@
    \"双引号 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."
    -}
    +
    {
    +  "url": "https://quickref.me",
    +  "msg" : "Hi,\n\"QuickRef.ME\"",
    +  "intro": "Share quick reference and cheat sheet for developers."
    +}
     

    无效字符串

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

    Have to be delimited by double quotes

    数字

    @@ -184,95 +184,95 @@
    类型说明
    Integer数字 1-9、0 和正数或负数
    Fraction0.3、3.9 等分数
    Exponent指数,如 e、e+、e-、E、E+、E

    示例

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

    无效的数字

    -
    { "foo": 0xFF }
    +
    { "foo": 0xFF }
     

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

    对象 Objects

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

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

    数组 Arrays

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

    [ 开始并以 ] 结束

    对象数组

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

    数组对象

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

    二维阵列

    -
    {
    -  "my_sequences": [
    -    [1, 2, 3],
    -    [4, 5, 6],
    -    [7, 8, 9, 0],
    -    [10, 11]
    -  ]
    -}
    +
    {
    +  "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
    -  }
    -}
    +
    {
    +  "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"
    -    }
    -  }
    -}
    +
    {
    +  "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
    -};
    +
    let myObject = {
    +  "name": "Jason",
    +  "last": "Doe",
    +  "age": 39,
    +  "gender": "M",
    +  "salary": 70000,
    +  "married": true
    +};
     

    @@ -307,32 +307,32 @@
    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
    -    ]
    -};
    +
    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
    +    ]
    +};
     

    @@ -367,32 +367,32 @@
    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
    -  }
    -];
    +
    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
    +  }
    +];
     

    @@ -426,14 +426,14 @@
    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
    -];
    +
    let myArray = [
    +  "Jason",
    +  "Doe",
    +  39,
    +  "M",
    +  70000,
    +  true
    +];
     

    diff --git a/docs/markdown.html b/docs/markdown.html index 4050d2c4..22be4bd2 100644 --- a/docs/markdown.html +++ b/docs/markdown.html @@ -38,123 +38,123 @@

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

    Markdown 快速参考

    标题 (atx 风格)

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

    标题 (setext 风格)

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

    块引用

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

    无序列表

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

    或者

    -
    - Item 1
    -- Item 2
    +
    - Item 1
    +- Item 2
     

    或者

    -
    + Item 1
    -+ Item 2
    +
    + Item 1
    ++ Item 2
     

    或者

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

    有序列表

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

    链接

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

    强调

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

    水平线

    连字符

    -
    ---
    +
    ---
     

    星号

    -
    ***
    +
    ***
     

    下划线

    -
    ___
    +
    ___
     

    代码

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

    内联代码

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

    表格

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

    简单的风格

    -
        左栏     |     中间栏     |     右栏
    -:----------:|:-------------:|:-----------:
    -  单元格 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)
    +
    +![Alt Text](url)
     

    带链接的图片

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

    参考风格

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

    反斜杠转义

    diff --git a/docs/npm.html b/docs/npm.html index 01b87cb2..a0e6ab05 100644 --- a/docs/npm.html +++ b/docs/npm.html @@ -189,19 +189,19 @@

    杂项功能

    将某人添加为所有者

    -
    npm owner add USERNAME PACKAGENAME
    +
    npm owner add USERNAME PACKAGENAME
     

    列出包

    -
    npm ls
    +
    npm ls
     

    向安装旧版本软件包的用户添加警告

    -
    npm deprecate PACKAGE@"< 0.2.0" "critical bug fixed in v0.2.0"
    +
    npm deprecate PACKAGE@"< 0.2.0" "critical bug fixed in v0.2.0"
     

    更新所有包或选定的包

    -
    npm update [-g] PACKAGE
    +
    npm update [-g] PACKAGE
     

    检查过时的包

    -
    npm outdated [PACKAGE]
    +
    npm outdated [PACKAGE]
     
    © 2022 Kenny Wang, All rights reserved.
    diff --git a/docs/package.json.html b/docs/package.json.html index c315b5f2..bfb2f968 100644 --- a/docs/package.json.html +++ b/docs/package.json.html @@ -44,9 +44,9 @@
  • yarnpkg 文档 (yarnpkg.com)
  • name

    -
    {
    -  "name": "my-awesome-package"
    -}
    +
    {
    +  "name": "my-awesome-package"
    +}
     

    规则

      @@ -56,9 +56,9 @@
    • 必须仅使用URL安全字符

    version

    -
    {
    -  "version": "1.0.0"
    -}
    +
    {
    +  "version": "1.0.0"
    +}
     

    包的当前版本,严格遵循 Semantic Versioning 2.0.0 语义化版本规范。

    Tips

    @@ -72,34 +72,34 @@

    如果没有 nameversion 字段,您的包将无法安装

    安装 name

    -
    yarn add [包名]
    -# or
    -npm install [包名]
    +
    yarn add [包名]
    +# or
    +npm install [包名]
     

    安装后存放位置

    -
    node_modules/[包名]
    +
    node_modules/[包名]
     

    npmjs 下载地址

    -
    https://registry.npmjs.org/[包名]/-/[包名]-[version].tgz
    +
    https://registry.npmjs.org/[包名]/-/[包名]-[version].tgz
     

    这是您的 的名称。 它在URL中使用,作为参数命令行,以及 node_modules 中的目录名。

    信息类字段

    description

    -
    {
    -  "description": "我的包的概要简短描述"
    -}
    +
    {
    +  "description": "我的包的概要简短描述"
    +}
     

    帮助使用者了解包的功能的字符串,包管理器也会把这个字符串作为搜索关键词。

    license

    所有包都应该指定许可证,以便让用户了解他们是在什么授权下使用此包,以及此包还有哪些附加限制。

    -
    {
    -  "license": "MIT",
    -  "license": "(MIT or GPL-3.0)",
    -  "license": "SEE LICENSE IN LICENSE_FILENAME.txt",
    -  "license": "UNLICENSED"
    -}
    +
    {
    +  "license": "MIT",
    +  "license": "(MIT or GPL-3.0)",
    +  "license": "SEE LICENSE IN LICENSE_FILENAME.txt",
    +  "license": "UNLICENSED"
    +}
     

    鼓励使用开源 (OSI-approved) 许可证,除非你有特别的原因不用它。 如果你开发的包是你工作的一部分,最好和公司讨论后再做决定。

    license字段必须是以下之一:

    @@ -110,119 +110,119 @@
  • 如果你不想在任何条款下授权其他人使用你的私有或未公开的包,一个 UNLICENSED 字符串。
  • keywords

    -
    {
    -  "keywords": [
    -    "short", "relevant", "keywords"
    -  ]
    -}
    +
    {
    +  "keywords": [
    +    "short", "relevant", "keywords"
    +  ]
    +}
     

    一个字符串数组,当在包管理器里搜索包时很有用。

    链接类字段

    各种指向项目文档、issues 上报,以及代码托管网站的链接字段。

    homepage

    -
    {
    -  "homepage": "https://your-package.org"
    -}
    +
    {
    +  "homepage": "https://your-package.org"
    +}
     

    是包的项目主页或者文档首页。

    repository

    -
    {
    -  "repository": {
    -    "type": "git", "url": "https://github.com/user/repo.git"
    -  },
    -  "repository": "github:user/repo",
    -  "repository": "gitlab:user/repo",
    -  "repository": "bitbucket:user/repo",
    -  "repository": "gist:a1b2c3d4e5f"
    -}
    +
    {
    +  "repository": {
    +    "type": "git", "url": "https://github.com/user/repo.git"
    +  },
    +  "repository": "github:user/repo",
    +  "repository": "gitlab:user/repo",
    +  "repository": "bitbucket:user/repo",
    +  "repository": "gist:a1b2c3d4e5f"
    +}
     

    包的实际代码所在的位置。

    bugs

    -
    {
    -  "bugs": "https://github.com/user/repo/issues"
    -}
    +
    {
    +  "bugs": "https://github.com/user/repo/issues"
    +}
     

    问题反馈系统的 URL,或者是 email 地址之类的链接。用户通过该途径向你反馈问题。

    项目维护类字段

    author

    项目的维护者。

    -
    {
    -  "author": {
    -    "name": "Your Name",
    -    "email": "you@xxx.com",
    -    "url": "http://your-x.com"
    -  },
    -  "author": "Your Name <you@xxx.com> (http://your-x.com)"
    -}
    +
    {
    +  "author": {
    +    "name": "Your Name",
    +    "email": "you@xxx.com",
    +    "url": "http://your-x.com"
    +  },
    +  "author": "Your Name <you@xxx.com> (http://your-x.com)"
    +}
     

    作者信息,一个人。

    contributors

    -
    {
    -  "contributors": [
    -    { "name": "Your Friend", "email": "friend@xxx.com", "url": "http://friends-xx.com" }
    -    { "name": "Other Friend", "email": "other@xxx.com", "url": "http://other-xx.com" }
    -  ],
    -  "contributors": [
    -    "Your Friend <friend@xxx.com> (http://friends-xx.com)",
    -    "Other Friend <other@xxx.com> (http://other-xx.com)"
    -  ]
    -}
    +
    {
    +  "contributors": [
    +    { "name": "Your Friend", "email": "friend@xxx.com", "url": "http://friends-xx.com" }
    +    { "name": "Other Friend", "email": "other@xxx.com", "url": "http://other-xx.com" }
    +  ],
    +  "contributors": [
    +    "Your Friend <friend@xxx.com> (http://friends-xx.com)",
    +    "Other Friend <other@xxx.com> (http://other-xx.com)"
    +  ]
    +}
     

    贡献者信息,可能很多人。

    文件类信息

    指定包含在项目中的文件,以及项目的入口文件。

    files

    -
    {
    -  "files": [
    -    "filename.js",
    -    "directory/",
    -    "glob/*.{js,json}"
    -  ]
    -}
    +
    {
    +  "files": [
    +    "filename.js",
    +    "directory/",
    +    "glob/*.{js,json}"
    +  ]
    +}
     

    项目包含的文件,可以是单独的文件、整个文件夹,或者通配符匹配到的文件。

    main

    -
    {
    -  "main": "filename.js"
    -}
    +
    {
    +  "main": "filename.js"
    +}
     

    项目的入口文件。

    man

    -
    {
    -  "man": "./man/doc.1",
    -  "man": ["./man/doc.1", "./man/doc.2"]
    -}
    +
    {
    +  "man": "./man/doc.1",
    +  "man": ["./man/doc.1", "./man/doc.2"]
    +}
     

    项目的入口文件。

    directories

    -
    {
    -  "directories": {
    -    "lib": "path/to/lib/",
    -    "bin": "path/to/bin/",
    -    "man": "path/to/man/",
    -    "doc": "path/to/doc/",
    -    "example": "path/to/example/"
    -  }
    -}
    +
    {
    +  "directories": {
    +    "lib": "path/to/lib/",
    +    "bin": "path/to/bin/",
    +    "man": "path/to/man/",
    +    "doc": "path/to/doc/",
    +    "example": "path/to/example/"
    +  }
    +}
     

    当你的包安装时,你可以指定确切的位置来放二进制文件、man pages、文档、例子等。

    bin

    -
    {
    -  "bin": "bin.js",
    -  "bin": {
    -    "命令名称": "bin/命令路径/命令名称.js",
    -    "other-command": "bin/other-command"
    -  }
    -}
    +
    {
    +  "bin": "bin.js",
    +  "bin": {
    +    "命令名称": "bin/命令路径/命令名称.js",
    +    "other-command": "bin/other-command"
    +  }
    +}
     

    随着项目一起被安装的可执行文件。

    types

    这是一个只在 TypeScript 中生效的字段,如果您的包有一个 main.js 文件,您还需要在 package.json 文件中指明主声明文件。 将 types 属性设置为指向 bundled 的声明文件。 例如:

    -
    {
    -  "types": "./lib/main.d.ts",
    -}
    +
    {
    +  "types": "./lib/main.d.ts",
    +}
     

    如果您的主声明文件名为 index.d.ts 并且位于包的根目录(index.js旁边),则不需要标记 types 属性,建议这样做。

    打包包字段

    @@ -235,37 +235,37 @@
  • 大多数 module 用例应该可以通过 esnext 处理。
  • browser 可以通过 esnext 的扩展版本来处理
  • -
    {
    -  "main": "main.js",
    -  "esnext": {
    -    "main": "main-esnext.js",
    -    "browser": "browser-specific-main-esnext.js"
    -  }
    -}
    +
    {
    +  "main": "main.js",
    +  "esnext": {
    +    "main": "main-esnext.js",
    +    "browser": "browser-specific-main-esnext.js"
    +  }
    +}
     

    另请参阅:通过 npm 交付未编译的源代码

    module

    pkg.module 将指向具有 ES2015 模块语法的模块,但仅指向目标环境支持的语法功能。 完整的描述在这里

    -
    {
    -  "module": "dist/my-package.esm.js"
    -}
    +
    {
    +  "module": "dist/my-package.esm.js"
    +}
     

    支持:rollup, webpack

    browser

    -
    "browser": {
    -    "module-a": "./shims/module-a.js",
    -    "./server/only.js": "./shims/client-only.js"
    -}
    +
    "browser": {
    +    "module-a": "./shims/module-a.js",
    +    "./server/only.js": "./shims/client-only.js"
    +}
     

    字段由模块作者提供,作为 JavaScript 包或组件工具的提示,用于打包模块以供客户端使用。 提案就在这里

    任务类字段

    包里还可以包含一些可执行脚本或者其他配置信息。

    scripts

    -
    {
    -  "scripts": {
    -    "build-project": "node build-project.js"
    -  }
    -}
    +
    {
    +  "scripts": {
    +    "build-project": "node build-project.js"
    +  }
    +}
     

    脚本是定义自动化开发相关任务的好方法,比如使用一些简单的构建过程或开发工具。 在 scripts 字段里定义的脚本,可以通过 yarn run <script> 命令来执行。 例如,上述 build-project 脚本可以通过 yarn run build-project 调用,并执行 node build-project.js

    有一些特殊的脚本名称。 如果定义了 preinstall 脚本,它会在包安装前被调用。 出于兼容性考虑,installpostinstallprepublish 脚本会在包完成安装后被调用。

    @@ -296,18 +296,18 @@

    参考文档:npm docs.

    config

    -
    {
    -  "config": {
    -    "port": "8080"
    -  }
    -}
    +
    {
    +  "config": {
    +    "port": "8080"
    +  }
    +}
     

    配置你的脚本的选项或参数。

    -
    {
    -  "scripts": {
    -    "run": "echo $npm_package_config_port"
    -  }
    -}
    +
    {
    +  "scripts": {
    +    "run": "echo $npm_package_config_port"
    +  }
    +}
     

    配置中的键作为环境变量公开给脚本(scripts)。

    依赖描述类字段

    @@ -315,164 +315,164 @@

    dependencies

    这些是你的包的开发版和发布版都需要的依赖。

    -
    {
    -  "dependencies": {
    -    "colors":   "*",
    -    "foo": "1.0.0 - 2.9999.9999",
    -    "bar": ">=1.0.2 <2.1.2",
    -    "baz": ">1.0.2 <=2.3.4",
    -    "boo": "2.0.1",
    -    "qux": "<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0",
    -    "asd": "http://asdf.com/asdf.tar.gz",
    -    "til": "~1.2",
    -    "elf": "~1.2.3",
    -    "two": "2.x",
    -    "thr": "3.3.x",
    -    "lat": "latest",
    -    "dyl": "file:./path/to/dyl",
    -    "pla": "https://github.com/user/project/tarball/branch",
    -    "stu": "git://github.com/user/project.git#commit-ish"
    -  }
    -}
    +
    {
    +  "dependencies": {
    +    "colors":   "*",
    +    "foo": "1.0.0 - 2.9999.9999",
    +    "bar": ">=1.0.2 <2.1.2",
    +    "baz": ">1.0.2 <=2.3.4",
    +    "boo": "2.0.1",
    +    "qux": "<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0",
    +    "asd": "http://asdf.com/asdf.tar.gz",
    +    "til": "~1.2",
    +    "elf": "~1.2.3",
    +    "two": "2.x",
    +    "thr": "3.3.x",
    +    "lat": "latest",
    +    "dyl": "file:./path/to/dyl",
    +    "pla": "https://github.com/user/project/tarball/branch",
    +    "stu": "git://github.com/user/project.git#commit-ish"
    +  }
    +}
     

    你可以指定一个确切的版本、一个最小的版本 (比如 >=) 或者一个版本范围 (比如 >= ... <)。 包也可以指向本地的一个目录文件夹。 参考文档:npm docs.

    workspaces

    -
    {
    -  "name": "my-workspaces-powered-project",
    -  "workspaces": [
    -    "./pkg/*",
    -    "packages/a",
    -    "packages/b"
    -  ]
    -}
    +
    {
    +  "name": "my-workspaces-powered-project",
    +  "workspaces": [
    +    "./pkg/*",
    +    "packages/a",
    +    "packages/b"
    +  ]
    +}
     

    支持从单个顶级根包中管理本地文件系统中的多个包。

    -
    ├┈┈ node_modules
    -┆  ├┈┈ a -> ../packages/a
    -┆  ╰┈┈ b -> ../packages/b
    -├┈┈ package-lock.json
    -├┈┈ package.json
    -╰┈┈ packages
    -   ├┈┈ a
    -   ┆   ╰┈┈ package.json
    -   ├┈┈ b
    -   ┆   ╰┈┈ package.json
    +
    ├┈┈ node_modules
    +┆  ├┈┈ a -> ../packages/a
    +┆  ╰┈┈ b -> ../packages/b
    +├┈┈ package-lock.json
    +├┈┈ package.json
    +╰┈┈ packages
    +   ├┈┈ a
    +   ┆   ╰┈┈ package.json
    +   ├┈┈ b
    +   ┆   ╰┈┈ package.json
     

    参考文档:workspaces

    devDependencies

    -
    {
    -  "devDependencies": {
    -    "package-2": "^0.4.2"
    -  }
    -}
    +
    {
    +  "devDependencies": {
    +    "package-2": "^0.4.2"
    +  }
    +}
     

    这些是只在你的包开发期间需要,但是生产环境不会被安装的包。

    peerDependencies

    -
    {
    -  "peerDependencies": {
    -    "package-3": "^2.7.18"
    -  }
    -}
    +
    {
    +  "peerDependencies": {
    +    "package-3": "^2.7.18"
    +  }
    +}
     

    平行依赖允许你说明你的包和其他包版本的兼容性。添加可选设置以消除丢失的对等依赖性警告,#6671

    optionalDependencies

    -
    {
    -  "optionalDependencies": {
    -    "package-5": "^1.6.1"
    -  }
    -}
    +
    {
    +  "optionalDependencies": {
    +    "package-5": "^1.6.1"
    +  }
    +}
     

    可选依赖可以用于你的包,但不是必需的。如果可选包没有找到,安装还可以继续。

    bundledDependencies

    -
    {
    -  "bundledDependencies": [
    -    "package-4"
    -  ]
    -}
    +
    {
    +  "bundledDependencies": [
    +    "package-4"
    +  ]
    +}
     

    打包依赖是发布你的包时将会一起打包的一个包名数组。

    peerDependenciesMeta

    -
    {
    -  "peerDependenciesMeta": {
    -    "node-sass": {
    -      "optional": true
    -    },
    -    "sass": {
    -      "optional": true
    -    },
    -    "fibers": {
    -      "optional": true
    -    }
    -  }
    -}
    +
    {
    +  "peerDependenciesMeta": {
    +    "node-sass": {
    +      "optional": true
    +    },
    +    "sass": {
    +      "optional": true
    +    },
    +    "fibers": {
    +      "optional": true
    +    }
    +  }
    +}
     

    系统

    你可以提供和你的包关联的系统级的信息,比如操作系统兼容性之类。

    engines

    指定使用你的包客户必须使用的版本,这将检查 process.versions 以及当前 yarn 版本。

    -
    {
    -  "engines": {
    -    "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0",
    -    "node": ">=4.4.7 <7.0.0",
    -    "zlib": "^1.2.8",
    -    "yarn": "^0.14.0"
    -  }
    -}
    +
    {
    +  "engines": {
    +    "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0",
    +    "node": ">=4.4.7 <7.0.0",
    +    "zlib": "^1.2.8",
    +    "yarn": "^0.14.0"
    +  }
    +}
     

    此检查遵守正常的 semver 规则,但有一个例外。 它允许预发布版本匹配未明确指定预发布的 semver。 例如,1.4.0-rc.0 匹配 >=1.3.0,但它与典型的 semver 检查不匹配。

    os

    -
    {
    -  "os": ["darwin", "linux"],
    -  "os": ["!win32"]
    -}
    +
    {
    +  "os": ["darwin", "linux"],
    +  "os": ["!win32"]
    +}
     

    此选项指定你的包的操作系统兼容性,它会检查 process.platform

    cpu

    -
    {
    -  "cpu": ["x64", "ia32"],
    -  "cpu": ["!arm", "!mips"]
    -}
    +
    {
    +  "cpu": ["x64", "ia32"],
    +  "cpu": ["!arm", "!mips"]
    +}
     

    使用这个选项指定你的包将只能在某些 CPU 体系架构上运行,这会检查 process.arch

    发布

    private

    -
    {
    -  "private": true
    -}
    +
    {
    +  "private": true
    +}
     

    如果你不想你的包发布到包管理器(npm 或者 私有包管理),设置为 true

    publishConfig

    这些配置值将在你的包发布时使用。比如,你可以给包打标签。

    -
    {
    -  "publishConfig": {
    -    "registry": "https://registry.npm.taobao.org"
    -  }
    -}
    +
    {
    +  "publishConfig": {
    +    "registry": "https://registry.npm.taobao.org"
    +  }
    +}
     

    这是一组将在发布时使用的配置值。 如果要设置标记,注册表或访问权限,则特别方便,以便确保给定的包未标记为 latest,发布到全局公共 registry 或默认情况下,作用域模块(@scoped)是私有的。

    可以覆盖任何配置值,但只有 tagregistryaccess 可能对于发布而言很重要,npm-config

    Yarn

    flat

    如果你的包只允许给定依赖的一个版本,你想强制和命令行上 yarn install --flat 相同的行为,把这个值设为 true

    -
    {
    -  "flat": true
    -}
    +
    {
    +  "flat": true
    +}
     

    请注意,如果你的 package.json 包含 "flat": true 并且其它包依赖你的包 (比如你在构建一个库,而不是应用), 其它那些包也需要在它们的 package.json 加上 "flat": true,或者在命令行上用 yarn install --flat 安装。

    resolutions

    -
    {
    -  "resolutions": {
    -    "transitive-package-1": "0.0.29",
    -    "transitive-package-2": "file:./local-forks/transitive-package-2",
    -    "dependencies-package-1/transitive-package-3": "^2.1.1"
    -  }
    -}
    +
    {
    +  "resolutions": {
    +    "transitive-package-1": "0.0.29",
    +    "transitive-package-2": "file:./local-forks/transitive-package-2",
    +    "dependencies-package-1/transitive-package-3": "^2.1.1"
    +  }
    +}
     

    允许您覆盖特定嵌套依赖项的版本。 有关完整规范,请参见选择性版本解析 RFC

    注意,yarn install --flat 命令将会自动在 package.json 文件里加入 resolutions 字段。

    diff --git a/docs/quickreference.html b/docs/quickreference.html index ff5e9b18..784d23f9 100644 --- a/docs/quickreference.html +++ b/docs/quickreference.html @@ -40,22 +40,22 @@

    本地编译预览

    简单的将仓库克隆下来本地调试页面展示。

    克隆仓库

    -
    git clone git@github.com:jaywcjlove/reference.git
    +
    git clone git@github.com:jaywcjlove/reference.git
     

    安装依赖编译生成 HTML 页面

    -
    npm i         # 安装依赖
    -npm run build # 编译输出 HTML
    -npm run start # 监听 md 文件编译输出 HTML
    +
    npm i         # 安装依赖
    +npm run build # 编译输出 HTML
    +npm run start # 监听 md 文件编译输出 HTML
     

    HTML 存放在仓库根目录下的 dist 目录中,将 dist/index.html 静态页面在浏览器中打开预览。

    介绍

    在备忘清单采用 HTML 注释语法,标识网站布局和一些样式,目的是为了在 GitHub 中也是正常毫无瑕疵的预览 Markdown

    -
    ### 卡片标题
    -<!--rehype:wrap-class=col-span-2-->
    -
    -卡片 Markdown 内容展示,下面注释语法为文字内容改变样式
    -<!--rehype:style=color: red;-->
    +
    ### 卡片标题
    +<!--rehype:wrap-class=col-span-2-->
    +
    +卡片 Markdown 内容展示,下面注释语法为文字内容改变样式
    +<!--rehype:style=color: red;-->
     

    使用 col-span-2 类标识,卡片占 2 列位置

    @@ -70,15 +70,15 @@

    <!--rehype: + key=value + & + key=value + -->
    标识开始 + 参数 + 分隔符 + 参数 + 标识结束

    示例

    -
    ### H2 部分
    -<!--rehype:body-class=cols-2-->
    -
    -### H3 部分
    -<!--rehype:wrap-class=row-span-2-->
    +
    ### H2 部分
    +<!--rehype:body-class=cols-2-->
    +
    +### H3 部分
    +<!--rehype:wrap-class=row-span-2-->
     

    示例,三行占位,标题红色

    -
    ### 标题
    -<!--rehype:wrap-class=row-span-3&style=color:red;-->
    +
    ### 标题
    +<!--rehype:wrap-class=row-span-3&style=color:red;-->
     

    参数说明

    @@ -109,44 +109,57 @@
    说明
    body-style包裹所有卡片外壳的样式
    body-class用于卡片栏布局,添加
    wrap-style卡片栏添加 CSS 样式
    wrap-class用于卡片占位,添加

    文字颜色

    -
    _我是红色_<!--rehype:style=color: red;-->
    -**加粗红色**<!--rehype:style=color: red;-->
    +
    _我是红色_<!--rehype:style=color: red;-->
    +**加粗红色**<!--rehype:style=color: red;-->
     

    上面添加注释样式,文字 我是红色 文字变

    文字大小

    -
    **加粗变大红色**
    -<!--rehype:style=color: red;font-size: 18px-->
    +
    **加粗变大红色**
    +<!--rehype:style=color: red;font-size: 18px-->
     

    上面添加注释样式,文字 加粗变大红色并且

    强制换行

    -
    \```js
    -function () {}
    -\```
    -<!--rehype:className=wrap-text -->
    +
    \```js
    +function () {}
    +\```
    +<!--rehype:className=wrap-text -->
     

    如果代码块内容太长,使用强制换行类解决

    展示表格表头

    -
    | Key | value | 
    -| ---- | ---- |
    -| `键` ||
    -<!--rehype:className=show-header-->
    +
    | Key | value | 
    +| ---- | ---- |
    +| `键` ||
    +<!--rehype:className=show-header-->
     

    注释配置添加 show-header 类,放置在表格下面,表头将被展示出来。

    +

    代码行高亮

    + +
    import React from "react";
    +import "./Student.css";
    +
    +export const Student = (
    +  <div className="Student"></div>
    +);
    +
    +

    上面 {1,4-5} 行代码高亮,下面是 Markdown 代码示例

    +
      ```jsx {1,4-5}
    +

    Tooltips

    鼠标移动到上面有提示Tooltips 的提示内容

    添加注释配置 <!--rehype:tooltips--> 添加一个 Tooltips 提示。

    H3 部分(卡片)背景颜色

    -
    ### H3 部分(卡片)背景颜色
    -<!--rehype:wrap-style=background: #00c69357;-->
    +
    ### H3 部分(卡片)背景颜色
    +<!--rehype:wrap-style=background: #00c69357;-->
     

    红色标题

    -
    ### 红色标题
    -<!--rehype:style=background:#e91e63;-->
    +
    ### 红色标题
    +<!--rehype:style=background:#e91e63;-->
     
    +

    在 H3 标题下面添加样式标注 <!--rehype:style=background:#e91e63;-->

    快捷键样式

    @@ -168,6 +181,11 @@
    Keyvalue
    快捷键说明
    快捷键说明

    列表添加 <!--rehype:className=shortcuts--> 样式类,展示快捷键样式。

    +

    代码行号

    +
    export const Student = (
    +  <div className="Student"></div>
    +);
    +

    内置类样式

    @@ -223,20 +241,20 @@

    布局

    H2 部分

    -
    H2 部分
    ----
    -
    -### 卡片 1 (H3 部分)
    -### 卡片 2 (H3 部分)
    -### 卡片 3 (H3 部分)
    +
    H2 部分
    +---
    +
    +### 卡片 1 (H3 部分)
    +### 卡片 2 (H3 部分)
    +### 卡片 3 (H3 部分)
     

    上面实例 H2 部分 标题下面有三个卡片,默认 3 栏布局。

    -
    H2 部分
    ----
    -<!--rehype:body-class=cols-2-->
    -### 卡片 1 (H3 部分)
    -### 卡片 2 (H3 部分)
    -### 卡片 3 (H3 部分)
    +
    H2 部分
    +---
    +<!--rehype:body-class=cols-2-->
    +### 卡片 1 (H3 部分)
    +### 卡片 2 (H3 部分)
    +### 卡片 3 (H3 部分)
     

    使用注释配置为 H2 部分 添加 col-span-2 类,将 3 栏布局变成 2 栏布局。

    @@ -271,23 +289,23 @@
    说明
    cols-11 栏卡片布局
    cols-22 栏卡片布局
    cols-33 栏卡片布局
    cols-44 栏卡片布局
    cols-55 栏卡片布局

    占位布局 style 写法

    -
    ### H3 部分
    -<!--rehype:wrap-style=grid-row: span 2/span 2;-->
    +
    ### H3 部分
    +<!--rehype:wrap-style=grid-row: span 2/span 2;-->
     

    放在 ### H3 部分 下面的注释配置,与 <!--rehype:wrap-class=row-span-2--> 相同,设置 2 行占位布局。

    卡片栏布局 style 写法

    -
    ## H2 部分
    -<!--rehype:body-style=grid-template-columns: repeat(2,minmax(0,1fr));-->
    +
    ## H2 部分
    +<!--rehype:body-style=grid-template-columns: repeat(2,minmax(0,1fr));-->
     

    放在 ## H2 部分 下面的注释配置,与 <!--rehype:body-class=cols-2--> 相同,设置 2 栏布局。

    H3 部分

    -
    ### 卡片 1 (H3 部分)
    -<!--rehype:wrap-class=row-span-2-->
    -### 卡片 2 (H3 部分)
    -<!--rehype:wrap-class=col-span-3-->
    -### 卡片 3 (H3 部分)
    +
    ### 卡片 1 (H3 部分)
    +<!--rehype:wrap-class=row-span-2-->
    +### 卡片 2 (H3 部分)
    +<!--rehype:wrap-class=col-span-3-->
    +### 卡片 3 (H3 部分)
     
    @@ -325,165 +343,165 @@
    说明
    col-span-22 列占位
    col-span-33 列占位
    col-span-44 列占位
    row-span-22 行占位
    row-span-33 行占位
    row-span-44 行占位

    卡片合并行布局 1

    -
    ╭┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈╮
    -┆   H3 Title 1  ┆
    -╰┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈╯
    -╭┈┈┈╮ ╭┈┈┈╮ ╭┈┈┈╮
    -2 ┆ ┆ 3 ┆ ┆ 4 ┆
    -╰┈┈┈╯ ╰┈┈┈╯ ╰┈┈┈╯
    +
    ╭┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈╮
    +┆   H3 Title 1  ┆
    +╰┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈╯
    +╭┈┈┈╮ ╭┈┈┈╮ ╭┈┈┈╮
    +2 ┆ ┆ 3 ┆ ┆ 4 ┆
    +╰┈┈┈╯ ╰┈┈┈╯ ╰┈┈┈╯
     

    上面布局效果 Markdown 源码:

    -
    ### H3 Title 1
    -<!--rehype:wrap-class=col-span-3-->
    -### Title 2
    -
    -### Title 3
    -
    -### Title 4
    +
    ### H3 Title 1
    +<!--rehype:wrap-class=col-span-3-->
    +### Title 2
    +
    +### Title 3
    +
    +### Title 4
     

    第一标题添加 col-span-3 占位类

    卡片列合并布局 2

    -
    ╭┈┈┈╮ ╭┈┈┈╮ ╭┈┈┈╮
    -1 ┆ ┆ 2 ┆ ┆ 3 ┆
    -┆   ┆ ╰┈┈┈╯ ╰┈┈┈╯
    -┆   ┆ ╭┈┈┈╮ ╭┈┈┈╮
    -┆   ┆ ┆ 4 ┆ ┆ 5 ┆
    -╰┈┈┈╯ ╰┈┈┈╯ ╰┈┈┈╯
    +
    ╭┈┈┈╮ ╭┈┈┈╮ ╭┈┈┈╮
    +1 ┆ ┆ 2 ┆ ┆ 3 ┆
    +┆   ┆ ╰┈┈┈╯ ╰┈┈┈╯
    +┆   ┆ ╭┈┈┈╮ ╭┈┈┈╮
    +┆   ┆ ┆ 4 ┆ ┆ 5 ┆
    +╰┈┈┈╯ ╰┈┈┈╯ ╰┈┈┈╯
     

    上面布局效果 Markdown 源码:

    -
    ### Title 1
    -<!--rehype:wrap-class=row-span-2-->
    -### Title 2
    -### Title 3
    -### Title 4
    -### Title 5
    +
    ### Title 1
    +<!--rehype:wrap-class=row-span-2-->
    +### Title 2
    +### Title 3
    +### Title 4
    +### Title 5
     

    Title 1 标题添加 row-span-2 占位类

    卡片列合并布局 3

    -
    ╭┈┈┈╮ ╭┈┈┈╮ ╭┈┈┈╮
    -1 ┆ ┆ 2 ┆ ┆ 3 ┆
    -╰┈┈┈╯ ┆   ┆ ╰┈┈┈╯
    -╭┈┈┈╮ ┆   ┆ ╭┈┈┈╮
    -4 ┆ ┆   ┆ ┆ 5 ┆
    -╰┈┈┈╯ ╰┈┈┈╯ ╰┈┈┈╯
    +
    ╭┈┈┈╮ ╭┈┈┈╮ ╭┈┈┈╮
    +1 ┆ ┆ 2 ┆ ┆ 3 ┆
    +╰┈┈┈╯ ┆   ┆ ╰┈┈┈╯
    +╭┈┈┈╮ ┆   ┆ ╭┈┈┈╮
    +4 ┆ ┆   ┆ ┆ 5 ┆
    +╰┈┈┈╯ ╰┈┈┈╯ ╰┈┈┈╯
     

    上面布局效果 Markdown 源码:

    -
    ### Title 1
    -### Title 2
    -<!--rehype:wrap-class=row-span-2-->
    -### Title 3
    -### Title 4
    -### Title 5
    +
    ### Title 1
    +### Title 2
    +<!--rehype:wrap-class=row-span-2-->
    +### Title 3
    +### Title 4
    +### Title 5
     

    Title 2 标题添加 row-span-2 占位类

    卡片列合并布局 4

    -
    ╭┈┈┈╮ ╭┈┈┈╮ ╭┈┈┈╮
    -1 ┆ ┆ 2 ┆ ┆ 3 ┆
    -╰┈┈┈╯ ╰┈┈┈╯ ┆   ┆
    -╭┈┈┈╮ ╭┈┈┈╮ ┆   ┆
    -4 ┆ ┆ 5 ┆ ┆   ┆
    -╰┈┈┈╯ ╰┈┈┈╯ ╰┈┈┈╯
    +
    ╭┈┈┈╮ ╭┈┈┈╮ ╭┈┈┈╮
    +1 ┆ ┆ 2 ┆ ┆ 3 ┆
    +╰┈┈┈╯ ╰┈┈┈╯ ┆   ┆
    +╭┈┈┈╮ ╭┈┈┈╮ ┆   ┆
    +4 ┆ ┆ 5 ┆ ┆   ┆
    +╰┈┈┈╯ ╰┈┈┈╯ ╰┈┈┈╯
     

    上面布局效果 Markdown 源码:

    -
    ### Title 1
    -### Title 2
    -### Title 3
    -<!--rehype:wrap-class=row-span-2-->
    -### Title 4
    -### Title 5
    +
    ### Title 1
    +### Title 2
    +### Title 3
    +<!--rehype:wrap-class=row-span-2-->
    +### Title 4
    +### Title 5
     

    Title 3 标题添加 row-span-2 占位类

    卡片列合并布局 5

    -
    ╭┈┈┈╮ ╭┈┈┈╮ ╭┈┈┈╮
    -1 ┆ ┆ 2 ┆ ┆ 3 ┆
    -╰┈┈┈╯ ╰┈┈┈╯ ╰┈┈┈╯ 
    -╭┈┈┈╮ ╭┈┈┈┈┈┈┈┈┈╮
    -4 ┆ ┆ 5       ┆
    -╰┈┈┈╯ ╰┈┈┈┈┈┈┈┈┈╯
    +
    ╭┈┈┈╮ ╭┈┈┈╮ ╭┈┈┈╮
    +1 ┆ ┆ 2 ┆ ┆ 3 ┆
    +╰┈┈┈╯ ╰┈┈┈╯ ╰┈┈┈╯ 
    +╭┈┈┈╮ ╭┈┈┈┈┈┈┈┈┈╮
    +4 ┆ ┆ 5       ┆
    +╰┈┈┈╯ ╰┈┈┈┈┈┈┈┈┈╯
     

    上面布局效果 Markdown 源码:

    -
    ### Title 1
    -### Title 2
    -### Title 3
    -### Title 4
    -### Title 5
    -<!--rehype:wrap-class=col-span-2-->
    +
    ### Title 1
    +### Title 2
    +### Title 3
    +### Title 4
    +### Title 5
    +<!--rehype:wrap-class=col-span-2-->
     

    Title 5 标题添加 col-span-2 占位类

    卡片列合并布局 6

    -
    ╭┈┈┈╮ ╭┈┈┈┈┈┈┈┈┈╮
    -1 ┆ ┆ 2       ┆
    -╰┈┈┈╯ ╰┈┈┈┈┈┈┈┈┈╯
    -╭┈┈┈╮ ╭┈┈┈╮ ╭┈┈┈╮
    -3 ┆ ┆ 4 ┆ ┆ 5 ┆
    -╰┈┈┈╯ ╰┈┈┈╯ ╰┈┈┈╯
    +
    ╭┈┈┈╮ ╭┈┈┈┈┈┈┈┈┈╮
    +1 ┆ ┆ 2       ┆
    +╰┈┈┈╯ ╰┈┈┈┈┈┈┈┈┈╯
    +╭┈┈┈╮ ╭┈┈┈╮ ╭┈┈┈╮
    +3 ┆ ┆ 4 ┆ ┆ 5 ┆
    +╰┈┈┈╯ ╰┈┈┈╯ ╰┈┈┈╯
     

    上面布局效果 Markdown 源码:

    -
    ### Title 1
    -### Title 2
    -<!--rehype:wrap-class=col-span-2-->
    -### Title 3
    -### Title 4
    -### Title 5
    +
    ### Title 1
    +### Title 2
    +<!--rehype:wrap-class=col-span-2-->
    +### Title 3
    +### Title 4
    +### Title 5
     

    Title 2 标题添加 col-span-2 占位类

    卡片列合并布局 7

    -
    ╭┈┈┈╮ ╭┈┈┈╮ ╭┈┈┈╮
    -1 ┆ ┆ 2 ┆ ┆ 3 ┆
    -╰┈┈┈╯ ╰┈┈┈╯ ╰┈┈┈╯
    -╭┈┈┈┈┈┈┈┈┈╮ ╭┈┈┈╮
    -4       ┆ ┆ 5 ┆
    -╰┈┈┈┈┈┈┈┈┈╯ ╰┈┈┈╯
    +
    ╭┈┈┈╮ ╭┈┈┈╮ ╭┈┈┈╮
    +1 ┆ ┆ 2 ┆ ┆ 3 ┆
    +╰┈┈┈╯ ╰┈┈┈╯ ╰┈┈┈╯
    +╭┈┈┈┈┈┈┈┈┈╮ ╭┈┈┈╮
    +4       ┆ ┆ 5 ┆
    +╰┈┈┈┈┈┈┈┈┈╯ ╰┈┈┈╯
     

    上面布局效果 Markdown 源码:

    -
    ### Title 1
    -### Title 2
    -### Title 3
    -### Title 4
    -<!--rehype:wrap-class=col-span-2-->
    -### Title 5
    +
    ### Title 1
    +### Title 2
    +### Title 3
    +### Title 4
    +<!--rehype:wrap-class=col-span-2-->
    +### Title 5
     

    Title 4 标题添加 col-span-2 占位类

    卡片列合并布局 8

    -
    ╭┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈╮
    -┆     H3 Title 1      ┆
    -╰┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈╯
    -╭┈┈┈╮ ╭┈┈┈╮ ╭┈┈┈╮ ╭┈┈┈╮
    -2 ┆ ┆ 3 ┆ ┆ 4 ┆ ┆ 5 ┆
    -╰┈┈┈╯ ╰┈┈┈╯ ╰┈┈┈╯ ╰┈┈┈╯
    +
    ╭┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈╮
    +┆     H3 Title 1      ┆
    +╰┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈╯
    +╭┈┈┈╮ ╭┈┈┈╮ ╭┈┈┈╮ ╭┈┈┈╮
    +2 ┆ ┆ 3 ┆ ┆ 4 ┆ ┆ 5 ┆
    +╰┈┈┈╯ ╰┈┈┈╯ ╰┈┈┈╯ ╰┈┈┈╯
     

    上面布局效果 Markdown 源码:

    -
    H2 部分
    -----
    -<!--rehype:body-class=cols-4-->
    -### Title 1
    -<!--rehype:wrap-class=col-span-4-->
    -### Title 2
    -### Title 3
    -### Title 4
    -### Title 5
    +
    H2 部分
    +----
    +<!--rehype:body-class=cols-4-->
    +### Title 1
    +<!--rehype:wrap-class=col-span-4-->
    +### Title 2
    +### Title 3
    +### Title 4
    +### Title 5
     

    H2 部分 标题添加 cols-4,和 Title 1 添加 col-span-4 合并栏

    卡片列合并布局 9

    -
    ╭┈┈┈┈┈┈┈┈┈╮ ╭┈┈┈╮
    -1       ┆ ┆ 2 ┆
    -┆         ┆ ╰┈┈┈╯
    -┆         ┆ ╭┈┈┈╮
    -┆         ┆ ┆ 3 ┆
    -╰┈┈┈┈┈┈┈┈┈╯ ╰┈┈┈╯
    -╭┈┈┈╮ ╭┈┈┈╮ ╭┈┈┈╮
    -4 ┆ ┆ 5 ┆ ┆ 6 ┆
    -╰┈┈┈╯ ╰┈┈┈╯ ╰┈┈┈╯
    +
    ╭┈┈┈┈┈┈┈┈┈╮ ╭┈┈┈╮
    +1       ┆ ┆ 2 ┆
    +┆         ┆ ╰┈┈┈╯
    +┆         ┆ ╭┈┈┈╮
    +┆         ┆ ┆ 3 ┆
    +╰┈┈┈┈┈┈┈┈┈╯ ╰┈┈┈╯
    +╭┈┈┈╮ ╭┈┈┈╮ ╭┈┈┈╮
    +4 ┆ ┆ 5 ┆ ┆ 6 ┆
    +╰┈┈┈╯ ╰┈┈┈╯ ╰┈┈┈╯
     

    上面布局效果 Markdown 源码:

    -
    ### Title 1
    -<!--rehype:wrap-class=col-span-2 row-span-2-->
    -### Title 2
    -### Title 3
    -### Title 4
    -### Title 5
    -### Title 6
    +
    ### Title 1
    +<!--rehype:wrap-class=col-span-2 row-span-2-->
    +### Title 2
    +### Title 3
    +### Title 4
    +### Title 5
    +### Title 6
     

    Title 1 标题添加 col-span-2row-span-2 占位类,使用 空格 间隔。

    表格

    @@ -634,44 +652,44 @@

    One

    -
    ...
    +
    ...
     

    Two

    -
    ...
    +
    ...
     

    Three

    -
    ...
    +
    ...
     

    Four

    -
    ...
    +
    ...
     

    Five

    -
    ...
    +
    ...
     

    H3 部分 - 占位效果展示

    row-span-2

    -
    ...
    +
    ...
     

    <!--rehype:wrap-class=row-span-2-->

    col-span-2

    -
    ...
    +
    ...
     

    <!--rehype:wrap-class=col-span-2-->

    红色标题

    -
    ...
    +
    ...
     

    <!--rehype:style=background:#e91e63;-->

    黄色标题

    -
    ...
    +
    ...
     

    <!--rehype:style=background:#d7a100;-->

    col-span-3

    -
    ...
    +
    ...
     

    卡片子项

    每个部分可以有以下子项:

    @@ -692,8 +710,8 @@

    这是一个包含段落的基本部分。

    H3 部分背景颜色

    -
    注释配置:
    -`<!--rehype:wrap-style=background: #1b5064;-->`
    +
    注释配置:
    +`<!--rehype:wrap-style=background: #1b5064;-->`
     
    © 2022 Kenny Wang, All rights reserved.
    diff --git a/docs/react.html b/docs/react.html index 554e9414..47add256 100644 --- a/docs/react.html +++ b/docs/react.html @@ -42,314 +42,314 @@ -
    import React from 'react'
    -import {createRoot} from 'react-dom/client'
    -import App from './App'
    +
    import React from 'react'
    +import {createRoot} from 'react-dom/client'
    +import App from './App'
     

    -
    const elm = document.getElementById('app')
    -const root = createRoot(elm);
    -root.render(<App />);
    +
    const elm = document.getElementById('app')
    +const root = createRoot(elm);
    +root.render(<App />);
     

    快速创建 React 项目 (CRA)

    -
    npx create-react-app my-app
    +
    npx create-react-app my-app
     

    导入多个导出

    -
    import React, {Component} from 'react'
    -import ReactDOM from 'react-dom'
    +
    import React, {Component} from 'react'
    +import ReactDOM from 'react-dom'
     

    -
    export class Hello extends Component {
    -  ...
    -}
    +
    export class Hello extends Component {
    +  ...
    +}
     

    使用 export 或者 export default 导出 Hello 组件

    -
    import { Hello } from './hello.js';
    -
    -const Example = <Hello />;
    +
    import { Hello } from './hello.js';
    +
    +const Example = <Hello />;
     

    使用 import 导入 Hello 组件,在示例中使用。

    React 组件中的 CSS

    -
    import React from "react";
    -import "./Student.css";
    -
    -export const Student = (
    -  <div className="Student"></div>
    -);
    +
    import React from "react";
    +import "./Student.css";
    +
    +export const Student = (
    +  <div className="Student"></div>
    +);
     

    注意:类属性 className

    -
    const divStyle = {
    -  backgroundImage: 'url(' + imgUrl + ')',
    -};
    -export const Student = (
    -  <div style={divStyle}></div>
    -);
    +
    const divStyle = {
    +  backgroundImage: 'url(' + imgUrl + ')',
    +};
    +export const Student = (
    +  <div style={divStyle}></div>
    +);
     

    属性

    -
    <Student name="Julie" age={23}
    -  pro={true} />
    +
    <Student name="Julie" age={23}
    +  pro={true} />
     

    函数组件 Student 中访问属性

    -
    function Student(props) {
    -  return <h1>Hello, {props.name}</h1>;
    -}
    +
    function Student(props) {
    +  return <h1>Hello, {props.name}</h1>;
    +}
     

    Class 组件 Student 中访问属性

    -
    class Student extends React.Component {
    -  render() {
    -    return (
    -      <h1>Hello, {this.props.name}</h1>
    -    );
    -  }
    -}
    +
    class Student extends React.Component {
    +  render() {
    +    return (
    +      <h1>Hello, {this.props.name}</h1>
    +    );
    +  }
    +}
     

    class 组件使用 this.props 访问传递给组件的属性。

    Children

    -
    function Example() {
    -  return (
    -    <AlertBox>
    -      <h1>您有待处理的通知</h1>
    -    </AlertBox>
    -  )
    -}
    +
    function Example() {
    +  return (
    +    <AlertBox>
    +      <h1>您有待处理的通知</h1>
    +    </AlertBox>
    +  )
    +}
     

    函数 AlertBox 组件

    -
    function AlertBox(props) {
    -  return (
    -    <div className="alert-box">
    -      {props.children}
    -    </div>
    -  );
    -}
    +
    function AlertBox(props) {
    +  return (
    +    <div className="alert-box">
    +      {props.children}
    +    </div>
    +  );
    +}
     

    -
    {props.children}
    +
    {props.children}
     

    Class AlertBox 组件,与函数组件 AlertBox 组件相同

    -
    class AlertBox extends React.Component {
    -  render () {
    -    return (
    -      <div className="alert-box">
    -        {this.props.children}
    -      </div>
    -    );
    -  }
    -}
    +
    class AlertBox extends React.Component {
    +  render () {
    +    return (
    +      <div className="alert-box">
    +        {this.props.children}
    +      </div>
    +    );
    +  }
    +}
     

    -
    {this.props.children}
    +
    {this.props.children}
     

    children 作为子组件的的属性传递。

    State

    函数中的 State,Hook 是 React 16.8 的新增特性

    -
    import { useState } from 'react';
    -
    -function Student() {
    -  // 声明一个叫 "count" 的 state 变量
    -  const [count, setCount] = useState(0);
    -  const click = () => setCount(count + 1);
    -
    -  return (
    -    <div>
    -      <p>您点击了 {count}</p>
    -      <button onClick={click}>
    -        点击我
    -      </button>
    -    </div>
    -  );
    -}
    +
    import { useState } from 'react';
    +
    +function Student() {
    +  const [count, setCount] = useState(0);
    +  const click = () => setCount(count + 1);
    +  return (
    +    <div>
    +      <p>您点击了 {count}</p>
    +      <button onClick={click}>
    +        点击我
    +      </button>
    +    </div>
    +  );
    +}
     

    使用 setState 更新状态,下面是函数组件读取状态

    -
    <p>您点击了 {count}</p>
    +
    <p>您点击了 {count}</p>
     

    Class 中的 State

    -
    import React from 'react';
    -
    -class Student extends React.Component {
    -  constructor(props) {
    -    super(props);
    -    this.state = {count: 1};
    -  }
    -  click() {
    -    const count = this.state.count;
    -    this.setState({ count: count + 1})
    -  }
    -  render() {
    -    return (
    -      <div>
    -        <button onClick={this.click}>
    -          点击我
    -        </button>
    -        <p>您点击了{this.state.count}</p>
    -      </div>
    -    );
    -  }
    -}
    +
    import React from 'react';
    +
    +class Student extends React.Component {
    +  constructor(props) {
    +    super(props);
    +    this.state = {count: 1};
    +    // 确保函数可以访问组件属性(ES2015)
    +    this.click = this.click.bind(this);
    +  }
    +  click() {
    +    const count = this.state.count;
    +    this.setState({ count: count + 1})
    +  }
    +  render() {
    +    return (
    +      <div>
    +        <button onClick={this.click}>
    +          点击我
    +        </button>
    +        <p>您点击了{this.state.count}</p>
    +      </div>
    +    );
    +  }
    +}
     

    使用 setState 更新状态,class 组件中不能使用 hooks。下面是 class 组件读取状态

    -
    <p>您点击了{this.state.count}</p>
    +
    <p>您点击了{this.state.count}</p>
     

    循环

    -
    const elm = ['one', 'two', 'three'];
    -function Student() {
    -  return (
    -    <ul>
    -      {elm.map((value, index) => (
    -        <li key={index}>{value}</li>
    -      ))}
    -    </ul>
    -  );
    -}
    +
    const elm = ['one', 'two', 'three'];
    +function Student() {
    +  return (
    +    <ul>
    +      {elm.map((value, index) => (
    +        <li key={index}>{value}</li>
    +      ))}
    +    </ul>
    +  );
    +}
     

    key 值在兄弟节点之间必须唯一

    事件监听

    -
    export default function Hello() {
    -  function handleClick(event) {
    -    event.preventDefault();
    -    alert("Hello World");
    -  }
    -
    -  return (
    -    <a href="/" onClick={handleClick}>
    -      Say Hi
    -    </a>
    -  );
    -}
    +
    export default function Hello() {
    +  function handleClick(event) {
    +    event.preventDefault();
    +    alert("Hello World");
    +  }
    +
    +  return (
    +    <a href="/" onClick={handleClick}>
    +      Say Hi
    +    </a>
    +  );
    +}
     

    函数注入

    -
    function addNumbers(x1, x2) {
    -  return x1 + x2;
    -}
    -
    -const element = (
    -  <div>
    -    {addNumbers(2, 5)}
    -  </div>
    -);
    +
    function addNumbers(x1, x2) {
    +  return x1 + x2;
    +}
    +
    +const element = (
    +  <div>
    +    {addNumbers(2, 5)}
    +  </div>
    +);
     

    嵌套

    -
    import { useState } from 'react'
    -import Avatar from './Avatar';
    -import Profile from './Profile';
    -
    -function Student() {
    -  const [count, setCount] = useState(0);
    -  return (
    -    <div>
    -      <Avatar src={count} />
    -      <Profile username={count} />
    -    </div>
    -  );
    -}
    +
    import { useState } from 'react'
    +import Avatar from './Avatar';
    +import Profile from './Profile';
    +
    +function Student() {
    +  const [count, setCount] = useState(0);
    +  return (
    +    <div>
    +      <Avatar src={count} />
    +      <Profile username={count} />
    +    </div>
    +  );
    +}
     

    Portals

    React 并没有创建一个新的 div。它只是把子元素渲染到 domNode 中。domNode 是一个可以在任何位置的有效 DOM 节点。

    -
    render() {
    -  return ReactDOM.createPortal(
    -    this.props.children,
    -    domNode
    -  );
    -}
    +
    render() {
    +  return ReactDOM.createPortal(
    +    this.props.children,
    +    domNode
    +  );
    +}
     

    提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案

    Fragment

    -
    import { Fragment } from 'react'
    -import Avatar from './Avatar';
    -import Profile from './Profile';
    -
    -const Student = () => (
    -  <Fragment>
    -    <Avatar src="./demo.jpg" />
    -    <Profile username="name" />
    -  </Fragment>
    -);
    +
    import { Fragment } from 'react'
    +import Avatar from './Avatar';
    +import Profile from './Profile';
    +
    +const Student = () => (
    +  <Fragment>
    +    <Avatar src="./demo.jpg" />
    +    <Profile username="name" />
    +  </Fragment>
    +);
     

    v16.2.0 开始 Fragment 可用于返回多个子节点,而无需向 DOM 添加额外的包装节点。或者使用 <></> 效果是一样的。

    -
    const Student = () => (
    -  <>
    -    <Avatar src="./demo.jpg" />
    -    <Profile username="name" />
    -  </>
    -);
    +
    const Student = () => (
    +  <>
    +    <Avatar src="./demo.jpg" />
    +    <Profile username="name" />
    +  </>
    +);
     

    查看: Fragments & strings

    返回字符串

    -
    render() {
    -  return 'Look ma, no spans!';
    -}
    +
    render() {
    +  return 'Look ma, no spans!';
    +}
     

    您可以只返回一个字符串。查看: Fragments & strings

    返回数组

    -
    const Student = () => [
    -  <li key="A">First item</li>,
    -  <li key="B">Second item</li>
    -];
    +
    const Student = () => [
    +  <li key="A">First item</li>,
    +  <li key="B">Second item</li>
    +];
     

    不要忘记 key!查看: Fragments & strings

    Refs 转发

    -
    const FancyButton = React.forwardRef(
    -  (props, ref) => (
    -    <button ref={ref} className="btn">
    -      {props.children}
    -    </button>
    -  )
    -);
    +
    const FancyButton = React.forwardRef(
    +  (props, ref) => (
    +    <button ref={ref} className="btn">
    +      {props.children}
    +    </button>
    +  )
    +);
     

    使用

    -
    // 你可以直接获取 DOM button 的 ref:
    -const ref = React.createRef();
    -
    -<FancyButton ref={ref}>
    -  点击我
    -</FancyButton>;
    +
    // 你可以直接获取 DOM button 的 ref:
    +const ref = React.createRef();
    +
    +<FancyButton ref={ref}>
    +  点击我
    +</FancyButton>;
     

    Class 组件内部使用 ref 属性

    -
    import {Component,createRef} from 'react'
    -
    -class MyComponent extends Component {
    -  constructor(props) {
    -    super(props);
    -    this.myRef = createRef();
    -  }
    -
    -  render() {
    -    return <div ref={this.myRef} />;
    -  }
    -}
    +
    import {Component,createRef} from 'react'
    +
    +class MyComponent extends Component {
    +  constructor(props) {
    +    super(props);
    +    this.myRef = createRef();
    +  }
    +
    +  render() {
    +    return <div ref={this.myRef} />;
    +  }
    +}
     

    提示:Refs 适用于类组件,但不适用于函数组件(除非您使用 useRef hook,请参阅hooks

    函数组件内部使用 ref 属性

    -
    function CustomTextInput(props) {
    -  // 这里必须声明 $input,这样 ref 才可以引用它
    -  const $input = useRef(null);
    -  function handleClick() {
    -    $input.current.focus();
    -  }
    -  return (
    -    <div>
    -      <input type="text" ref={$input} />
    -      <input
    -        type="button" value="聚焦文本输入"
    -        onClick={handleClick}
    -      />
    -    </div>
    -  );
    -}
    +
    function CustomTextInput(props) {
    +  // 这里必须声明 $input,这样 ref 才可以引用它
    +  const $input = useRef(null);
    +  function handleClick() {
    +    $input.current.focus();
    +  }
    +  return (
    +    <div>
    +      <input type="text" ref={$input} />
    +      <input
    +        type="button" value="聚焦文本输入"
    +        onClick={handleClick}
    +      />
    +    </div>
    +  );
    +}
     

    严格模式 StrictMode

    -
    <div>
    -  <Header />
    -  <React.StrictMode>
    -    <div>
    -      <ComponentOne />
    -      <ComponentTwo />
    -    </div>
    -  </React.StrictMode>
    -  <Footer />
    -</div>
    +
    <div>
    +  <Header />
    +  <React.StrictMode>
    +    <div>
    +      <ComponentOne />
    +      <ComponentTwo />
    +    </div>
    +  </React.StrictMode>
    +  <Footer />
    +</div>
     

      @@ -364,9 +364,9 @@

    Profiler

    测量一个 React 应用多久渲染一次以及渲染一次的 代价

    -
    <Profiler id="Navigation" onRender={callback}>
    -  <Navigation {...props} />
    -</Profiler>
    +
    <Profiler id="Navigation" onRender={callback}>
    +  <Navigation {...props} />
    +</Profiler>
     

    为了分析 Navigation 组件和它的子代。应该在需要时才去使用它。

    @@ -425,251 +425,251 @@

    默认值

    Class 组件默认 props

    -
    class CustomButton extends React.Component {
    -  // ...
    -}
    -CustomButton.defaultProps = {
    -  color: 'blue'
    -};
    +
    class CustomButton extends React.Component {
    +  // ...
    +}
    +CustomButton.defaultProps = {
    +  color: 'blue'
    +};
     

    使用

    -
    <CustomButton /> ;
    +
    <CustomButton /> ;
     

    不传值 props.color 将自动设置为 blue

    Class 组件默认 state

    -
    class Hello extends Component {
    -  constructor (props) {
    -    super(props)
    -    this.state = { visible: true }
    -  }
    -}
    +
    class Hello extends Component {
    +  constructor (props) {
    +    super(props)
    +    this.state = { visible: true }
    +  }
    +}
     

    在构造 constructor()中设置默认状态。

    -
    class Hello extends Component {
    -  state = { visible: true }
    -}
    +
    class Hello extends Component {
    +  state = { visible: true }
    +}
     

    函数组件默认 props

    -
    function CustomButton(props) {
    -  const { color = 'blue' } = props;
    -  return <div>{color}</div>
    -}
    +
    function CustomButton(props) {
    +  const { color = 'blue' } = props;
    +  return <div>{color}</div>
    +}
     

    函数组件默认 state

    -
    function CustomButton() {
    -  const [color, setColor]=useState('blue')
    -  return <div>{color}</div>
    -}
    +
    function CustomButton() {
    +  const [color, setColor]=useState('blue')
    +  return <div>{color}</div>
    +}
     

    JSX

    介绍

    JSX 仅仅只是 React.createElement(component, props, ...children) 函数的语法糖

    -
    <MyButton color="blue" shadowSize={2}>
    -  点击我
    -</MyButton>
    +
    <MyButton color="blue" shadowSize={2}>
    +  点击我
    +</MyButton>
     

    会编译为

    -
    React.createElement(
    -  MyButton,
    -  {color: 'blue', shadowSize: 2},
    -  '点击我'
    -);
    +
    React.createElement(
    +  MyButton,
    +  {color: 'blue', shadowSize: 2},
    +  '点击我'
    +);
     

    没有子节点

    -
    <div className="sidebar" />
    +
    <div className="sidebar" />
     

    会编译为

    -
    React.createElement(
    -  'div',
    -  {className: 'sidebar'}
    -)
    +
    React.createElement(
    +  'div',
    +  {className: 'sidebar'}
    +)
     

    JSX 点语法

    -
    const Menu = ({ children }) => (
    -  <div className="menu">{children}<div>
    -);
    -
    -Menu.Item = ({ children }) => (
    -  <div>{children}<div>
    -);
    -
    -<Menu>
    -  <Menu.Item>菜单一</Menu.Item>
    -  <Menu.Item>菜单二</Menu.Item>
    -<Menu>
    +
    const Menu = ({ children }) => (
    +  <div className="menu">{children}<div>
    +);
    +
    +Menu.Item = ({ children }) => (
    +  <div>{children}<div>
    +);
    +
    +<Menu>
    +  <Menu.Item>菜单一</Menu.Item>
    +  <Menu.Item>菜单二</Menu.Item>
    +<Menu>
     

    JSX Element

    -
    let element = <h1>Hello, world!</h1>;
    -let emptyHeading = <h1 />;
    -
    -const root = ReactDOM.createRoot(
    -  document.getElementById('root')
    -);
    -
    -const element = <h1>Hello, world</h1>;
    -root.render(element);
    +
    let element = <h1>Hello, world!</h1>;
    +let emptyHeading = <h1 />;
    +
    +const root = ReactDOM.createRoot(
    +  document.getElementById('root')
    +);
    +
    +const element = <h1>Hello, world</h1>;
    +root.render(element);
     

    参考:渲染元素

    JSX 属性

    -
    const avatarUrl = "img/picture.jpg"
    -const element = <img src={avatarUrl} />;
    -
    -const element = (
    -  <button className="btn">
    -    点击我
    -  </button>
    -);
    +
    const avatarUrl = "img/picture.jpg"
    +const element = <img src={avatarUrl} />;
    +
    +const element = (
    +  <button className="btn">
    +    点击我
    +  </button>
    +);
     

    注意:类属性 className

    JSX 表达式

    -
    let name = '张三';
    -let element = <h1>Hello, {name}</h1>;
    -
    -function fullName(firstName, lastName) {
    -  return firstName + ' ' + lastName;
    -}
    -let element = (
    -  <h1>
    -    Hello, {fullName('三', '张')}
    -  </h1>
    -);
    +
    let name = '张三';
    +let element = <h1>Hello, {name}</h1>;
    +
    +function fullName(firstName, lastName) {
    +  return firstName + ' ' + lastName;
    +}
    +let element = (
    +  <h1>
    +    Hello, {fullName('三', '张')}
    +  </h1>
    +);
     

    JSX style

    -
    const divStyle = {
    -  color: 'blue',
    -  backgroundImage: 'url(' + imgUrl + ')',
    -};
    -function MyComponent() {
    -  return <div style={divStyle}>组件</div>;
    -}
    +
    const divStyle = {
    +  color: 'blue',
    +  backgroundImage: 'url(' + imgUrl + ')',
    +};
    +function MyComponent() {
    +  return <div style={divStyle}>组件</div>;
    +}
     

    JSX dangerouslySetInnerHTML

    -
    const markup = {__html: '我 &middot; 你' };
    -
    -const MyComponent = () => (
    -  <div dangerouslySetInnerHTML={markup} />
    -);
    +
    const markup = {__html: '我 &middot; 你' };
    +
    +const MyComponent = () => (
    +  <div dangerouslySetInnerHTML={markup} />
    +);
     

    dangerouslySetInnerHTML 是 React 为浏览器 DOM 提供 innerHTML 的替换方案。

    JSX htmlFor

    -
    const MyComponent = () => (
    -  <div>
    -    <input type="radio" id="ab" name="v">
    -    <label for="ab">HTML</label>
    -  </div>
    -);
    +
    const MyComponent = () => (
    +  <div>
    +    <input type="radio" id="ab" name="v">
    +    <label for="ab">HTML</label>
    +  </div>
    +);
     

    forJS 中是保留字,JSX 元素使用了 htmlFor 代替

    JSX defaultValue

    非受控组件的属性,设置组件第一次挂载时的 value

    -
    <textarea defaultValue="Hello" />
    +
    <textarea defaultValue="Hello" />
     

    <input><select><textarea> 支持 value 属性

    JSX defaultChecked

    非受控组件的属性,设置组件是否被选中

    -
    <input type="radio" defaultChecked />
    +
    <input type="radio" defaultChecked />
     

    类型为 checkboxradio 时,组件支持 checked 属性

    JSX className

    属性用于指定 CSSclass

    -
    <div className="warp">...</div>
    +
    <div className="warp">...</div>
     

    React 中使用 Web Components 使用 class 属性代替

    JSX 条件渲染

    -
    import React from "react";
    -
    -function formatName(user) {
    -  return user.firstName 
    -    + ' ' 
    -    + user.lastName;
    -}
    -
    -export function Greeting(user) {
    -  if (user) {
    -    return (
    -      <h1>你好, {formatName(user)}!</h1>
    -    );
    -  }
    -  return (
    -    <h1>你好, 先生。</h1>
    -  );
    -}
    +
    import React from "react";
    +
    +function formatName(user) {
    +  return user.firstName 
    +    + ' ' 
    +    + user.lastName;
    +}
    +
    +export function Greeting(user) {
    +  if (user) {
    +    return (
    +      <h1>你好, {formatName(user)}!</h1>
    +    );
    +  }
    +  return (
    +    <h1>你好, 先生。</h1>
    +  );
    +}
     

    注意:组件必须总是返回一些东西。

    使用

    -
    <Greeting firstName="" lastName="" />
    +
    <Greeting firstName="" lastName="" />
     

    JSX 三目运算符 / 与运算符 &&

    -
    export default function Weather(props) {
    -  const isLoggedIn = props.isLoggedIn;
    -  return (
    -    <div>
    -      <b>{isLoggedIn ? '已' : '未'}</b>登录。
    -    </div>
    -  );
    -}
    +
    export default function Weather(props) {
    +  const isLoggedIn = props.isLoggedIn;
    +  return (
    +    <div>
    +      <b>{isLoggedIn ? '已' : '未'}</b>登录。
    +    </div>
    +  );
    +}
     

    -
    {isShow && <div>内容</div>}
    +
    {isShow && <div>内容</div>}
     

    JSX 组件

    -
    <Dropdown>
    -  下拉列表
    -  <Menu>
    -    <Menu.Item>菜单一</Menu.Item>
    -    <Menu.Item>菜单二</Menu.Item>
    -    <Menu.Item>菜单三</Menu.Item>
    -  </Menu>
    -</Dropdown>
    +
    <Dropdown>
    +  下拉列表
    +  <Menu>
    +    <Menu.Item>菜单一</Menu.Item>
    +    <Menu.Item>菜单二</Menu.Item>
    +    <Menu.Item>菜单三</Menu.Item>
    +  </Menu>
    +</Dropdown>
     

    组件名称以大驼峰式命名。

    JSX 元素变量

    -
    function Greeting(props) {
    -  let button;
    -  if (props.isLoggedIn) {
    -    button = <UserGreeting />;
    -  } else {
    -    button = <GuestGreeting />;
    -  }
    -  return <div>{button}</div>;
    -}
    +
    function Greeting(props) {
    +  let button;
    +  if (props.isLoggedIn) {
    +    button = <UserGreeting />;
    +  } else {
    +    button = <GuestGreeting />;
    +  }
    +  return <div>{button}</div>;
    +}
     

    JSX 注释

    -
    function Student() {
    -  const [count, setCount] = useState(0);
    -  return (
    -    <Fragment>
    -      {/* 这里写注释 */}
    -    </Fragment>
    -  );
    -}
    +
    function Student() {
    +  const [count, setCount] = useState(0);
    +  return (
    +    <Fragment>
    +      {/* 这里写注释 */}
    +    </Fragment>
    +  );
    +}
     

    组件

    函数组件

    -
    import React from 'react';
    -
    -const UserName = () => <h1>Kenny</h1>;
    -
    -export default function UserProfile() {
    -  return (
    -    <div className="UserProfile">
    -      <div>Hello</div>  
    -      <UserName />
    -    </div>
    -  );
    -}
    +
    import React from 'react';
    +
    +const UserName = () => <h1>Kenny</h1>;
    +
    +export default function UserProfile() {
    +  return (
    +    <div className="UserProfile">
    +      <div>Hello</div>  
    +      <UserName />
    +    </div>
    +  );
    +}
     

    注意:每个组件都需要一个根元素,更多说明

    Class 组件

    -
    class Welcome extends React.Component {
    -  render() {
    -    return <h1>{this.props.name}</h1>;
    -  }
    -}
    +
    class Welcome extends React.Component {
    +  render() {
    +    return <h1>{this.props.name}</h1>;
    +  }
    +}
     

    Class 组件 API

    @@ -735,114 +735,114 @@
    :--
    this.props组件接受参数
    this.state组件内状态

    Pure 组件

    -
    import React, {PureComponent} from 'react'
    -
    -class MessageBox extends PureComponent {
    -  ···
    -}
    +
    import React, {PureComponent} from 'react'
    +
    +class MessageBox extends PureComponent {
    +  ···
    +}
     

    高阶组件

    -
    import React, { Component } from 'react';
    -// 高阶组件 with
    -const with = data => WrappedComponent => {
    -  return class extends Component {
    -    constructor(props) {
    -      super(props);
    -    }
    -    render() {
    -      return (
    -        <WrappedComponent data={data} />
    -      )
    -    }
    -  }
    -}
    +
    import React, { Component } from 'react';
    +// 高阶组件 with
    +const with = data => WrappedComponent => {
    +  return class extends Component {
    +    constructor(props) {
    +      super(props);
    +    }
    +    render() {
    +      return (
    +        <WrappedComponent data={data} />
    +      )
    +    }
    +  }
    +}
     

    使用高阶组件

    -
    const LowComponent = (props) => (
    -  <div>{props.data}</div>
    -);
    -
    -const MyComp = with('Hello')(LowComponent)
    +
    const LowComponent = (props) => (
    +  <div>{props.data}</div>
    +);
    +
    +const MyComp = with('Hello')(LowComponent)
     

    包含关系

    -
    function FancyBorder(props) {
    -  return (
    -    <div className={'Fancy'+props.color}>
    -      {props.children}
    -    </div>
    -  );
    -}
    +
    function FancyBorder(props) {
    +  return (
    +    <div className={'Fancy'+props.color}>
    +      {props.children}
    +    </div>
    +  );
    +}
     

    组件可以通过 JSX 嵌套

    -
    function WelcomeDialog() {
    -  return (
    -    <FancyBorder color="blue">
    -      <h1 className="title">欢迎</h1>
    -      <p className="message">
    -        感谢您访问我们的宇宙飞船
    -      </p>
    -    </FancyBorder>
    -  );
    -}
    +
    function WelcomeDialog() {
    +  return (
    +    <FancyBorder color="blue">
    +      <h1 className="title">欢迎</h1>
    +      <p className="message">
    +        感谢您访问我们的宇宙飞船
    +      </p>
    +    </FancyBorder>
    +  );
    +}
     

    作为参数传递

    -
    function SplitPane(props) {
    -  return (
    -    <div className="SplitPane">
    -      <div className="left">
    -        {props.left}
    -      </div>
    -      <div className="right">
    -        {props.right}
    -      </div>
    -    </div>
    -  );
    -}
    -
    -function App() {
    -  return (
    -    <SplitPane
    -      left={<Contacts />}
    -      right={<Chat />}
    -    />
    -  );
    -}
    +
    function SplitPane(props) {
    +  return (
    +    <div className="SplitPane">
    +      <div className="left">
    +        {props.left}
    +      </div>
    +      <div className="right">
    +        {props.right}
    +      </div>
    +    </div>
    +  );
    +}
    +
    +function App() {
    +  return (
    +    <SplitPane
    +      left={<Contacts />}
    +      right={<Chat />}
    +    />
    +  );
    +}
     

    给组件 SplitPane 传递 leftright 两个组件参数

    嵌入内部组件

    -
    import React from 'react';
    -import UserAvatar from "./UserAvatar";
    -
    -export default function UserProfile() {
    -  return (
    -    <div className="UserProfile">
    -      <UserAvatar />
    -      <UserAvatar />
    -    </div>
    -  );
    -}
    +
    import React from 'react';
    +import UserAvatar from "./UserAvatar";
    +
    +export default function UserProfile() {
    +  return (
    +    <div className="UserProfile">
    +      <UserAvatar />
    +      <UserAvatar />
    +    </div>
    +  );
    +}
     

    注意:假设 UserAvatarUserAvatar.js 中声明

    嵌入外部组件

    -
    import React from 'react';
    -import {Button} from 'uiw';
    -export default function UserProfile() {
    -  return (
    -    <div className="UserProfile">
    -      <Button type="primary">
    -        主要按钮
    -      </Button>
    -    </div>
    -  );
    -}
    +
    import React from 'react';
    +import {Button} from 'uiw';
    +export default function UserProfile() {
    +  return (
    +    <div className="UserProfile">
    +      <Button type="primary">
    +        主要按钮
    +      </Button>
    +    </div>
    +  );
    +}
     
    -

    注意:外部组件在 npmjs.com 上找到,需要先安装导入

    +

    注意:uiw 组件在 npmjs.com 上找到,需要先安装导入

    生命周期

    Hooks

    PropTypes 属性类型检查

    PropTypes

    -
    import PropTypes from 'prop-types'
    +
    import PropTypes from 'prop-types'
     

    @@ -1003,113 +1003,113 @@
    :--
    (···).isRequired必需的

    请参阅:使用 PropTypes 进行类型检查

    基本类型

    -
    MyComponent.propTypes = {
    -  email:      PropTypes.string,
    -  seats:      PropTypes.number,
    -  callback:   PropTypes.func,
    -  isClosed:   PropTypes.bool,
    -  any:        PropTypes.any
    -  symbol:     PropTypes.symbol,
    -}
    +
    MyComponent.propTypes = {
    +  email:      PropTypes.string,
    +  seats:      PropTypes.number,
    +  callback:   PropTypes.func,
    +  isClosed:   PropTypes.bool,
    +  any:        PropTypes.any
    +  symbol:     PropTypes.symbol,
    +}
     

    你可以将属性声明为 JS 原生类型,默认都是可选的。

    必需的

    -
    MyComponent.propTypes = {
    -  // 确保这个 prop 没有被提供时,会打印警告信息
    -  requiredFunc: PropTypes.func.isRequired,
    -
    -  // 任意类型的必需数据
    -  requiredAny: PropTypes.any.isRequired,
    -}
    +
    MyComponent.propTypes = {
    +  // 确保这个 prop 没有被提供时,会打印警告信息
    +  requiredFunc: PropTypes.func.isRequired,
    +
    +  // 任意类型的必需数据
    +  requiredAny: PropTypes.any.isRequired,
    +}
     

    你可以在任何 PropTypes 属性后面加上 isRequired

    枚举

    -
    MyComponent.propTypes = {
    -  // 只能是特定的值,枚举类型。
    -  optionalEnum: PropTypes.oneOf([
    -    'News', 'Photos'
    -  ]),
    -  // 一个对象可以是几种类型中的任意一个类型
    -  optionalUnion: PropTypes.oneOfType([
    -    PropTypes.string,
    -    PropTypes.number,
    -    PropTypes.instanceOf(Message)
    -  ]),
    -}
    +
    MyComponent.propTypes = {
    +  // 只能是特定的值,枚举类型。
    +  optionalEnum: PropTypes.oneOf([
    +    'News', 'Photos'
    +  ]),
    +  // 一个对象可以是几种类型中的任意一个类型
    +  optionalUnion: PropTypes.oneOfType([
    +    PropTypes.string,
    +    PropTypes.number,
    +    PropTypes.instanceOf(Message)
    +  ]),
    +}
     

    元素 Elements

    -
    MyComponent.propTypes = {
    -  // 任何可被渲染的元素
    -  // (包括数字、字符串、元素或数组)
    -  // (或 Fragment) 也包含这些类型。
    -  node: PropTypes.node,
    -
    -  // 一个 React 元素。
    -  element: PropTypes.element,
    -
    -  // 一个 React 元素类型(即,MyComponent)
    -  elementType: PropTypes.elementType,
    -}
    +
    MyComponent.propTypes = {
    +  // 任何可被渲染的元素
    +  // (包括数字、字符串、元素或数组)
    +  // (或 Fragment) 也包含这些类型。
    +  node: PropTypes.node,
    +
    +  // 一个 React 元素。
    +  element: PropTypes.element,
    +
    +  // 一个 React 元素类型(即,MyComponent)
    +  elementType: PropTypes.elementType,
    +}
     

    对象 Object

    -
    MyComponent.propTypes = {
    -  // 可以指定一个对象由某一类型的值组成
    -  objectOf: PropTypes.objectOf(
    -    PropTypes.number
    -  ),
    -  // 可以指定一个对象由特定的类型值组成
    -  objectWithShape: PropTypes.shape({
    -    color: PropTypes.string,
    -    fontSize: PropTypes.number
    -  }),
    -  // 带有额外属性警告的对象
    -  objectWithStrictShape: PropTypes.exact({
    -    name: PropTypes.string,
    -    quantity: PropTypes.number
    -  }),
    -}
    +
    MyComponent.propTypes = {
    +  // 可以指定一个对象由某一类型的值组成
    +  objectOf: PropTypes.objectOf(
    +    PropTypes.number
    +  ),
    +  // 可以指定一个对象由特定的类型值组成
    +  objectWithShape: PropTypes.shape({
    +    color: PropTypes.string,
    +    fontSize: PropTypes.number
    +  }),
    +  // 带有额外属性警告的对象
    +  objectWithStrictShape: PropTypes.exact({
    +    name: PropTypes.string,
    +    quantity: PropTypes.number
    +  }),
    +}
     

    自定义验证器

    -
    MyComponent.propTypes = {
    -  custom: (props, propName, compName) => {
    -    if (!/matchm/.test(props[propName])) {
    -      // 它在验证失败时应返回一个 Error 对象
    -      return new Error(
    -        '无效的prop `'
    -        ` \`${propName}\` 提供给` + 
    -        ` \`${compName}\`。验证失败。`
    -      );
    -
    -    }
    -  },
    -}
    +
    MyComponent.propTypes = {
    +  custom: (props, propName, compName) => {
    +    if (!/matchm/.test(props[propName])) {
    +      // 它在验证失败时应返回一个 Error 对象
    +      return new Error(
    +        '无效的prop `'
    +        ` \`${propName}\` 提供给` + 
    +        ` \`${compName}\`。验证失败。`
    +      );
    +
    +    }
    +  },
    +}
     

    请不要使用 console.warn 或抛出异常,因为这在 oneOfType 中不会起作用。

    自定义的 arrayOfobjectOf 验证器

    -
    MyComponent.propTypes = {
    -  arrayProp: PropTypes.arrayOf((propValue, key, componentName, location, propFullName) => {
    -    if (!/matchme/.test(propValue[key])) {
    -      // 它应该在验证失败时返回一个 Error 对象。
    -      return new Error(
    -        'Invalid prop `' + propFullName + '` supplied to' +
    -        ' `' + componentName + '`. Validation failed.'
    -      );
    -    }
    -  })
    -}
    +
    MyComponent.propTypes = {
    +  arrayProp: PropTypes.arrayOf((propValue, key, componentName, location, propFullName) => {
    +    if (!/matchme/.test(propValue[key])) {
    +      // 它应该在验证失败时返回一个 Error 对象。
    +      return new Error(
    +        'Invalid prop `' + propFullName + '` supplied to' +
    +        ' `' + componentName + '`. Validation failed.'
    +      );
    +    }
    +  })
    +}
     

    propValue 是数组或对象本身,key 是他们当前的键。

    数组

    -
    MyComponent.propTypes = {
    -  arr: PropTypes.arrayOf(PropTypes.number),
    -};
    +
    MyComponent.propTypes = {
    +  arr: PropTypes.arrayOf(PropTypes.number),
    +};
     

    可以指定一个数组由某一类型的元素组成

    验证类的实例

    -
    MyComponent.propTypes = {
    -  message: PropTypes.instanceOf(Message),
    -};
    +
    MyComponent.propTypes = {
    +  message: PropTypes.instanceOf(Message),
    +};
     

    声明 message 为类的实例

    另见

    diff --git a/docs/regex.html b/docs/regex.html index ea1f4368..88937917 100644 --- a/docs/regex.html +++ b/docs/regex.html @@ -1269,7 +1269,7 @@
    范例说明
    (?= )向前看,如果你能提前找到
    (?! )向前看,如果你找不到前面
    (?<= )向后看,如果你能找到后面
    (?<! )向后看,如果你找不到后面
    \b\w+?(?=ing\b)匹配 warbling, string, fishing, ...
    \b(?!\w+ing\b)\w+\b不以“ing”结尾的单词
    (?<=\bpre).*?\b 匹配 pretend、present、prefix、...
    \b\w{3}(?<!pre)\w*?\b不以“pre”开头的词
    \b\w+(?<!ing)\b匹配不以“ing”结尾的单词

    If-then-else

    匹配 Mr.Ms. 如果单词 her 稍后在字符串中

    -
    M(?(?=.*?\bher\b)s|r)\.
    +
    M(?(?=.*?\bher\b)s|r)\.
     

    需要环顾 IF 条件

    基础实例

    @@ -1742,47 +1742,47 @@

    Python 中的正则表达式

    入门

    导入正则表达式模块

    -
    import re
    +
    import re
     

    实例

    re.search()

    -
    >>> sentence = 'This is a sample string'
    ->>> bool(re.search(r'this', sentence, flags=re.I))
    -True
    ->>> bool(re.search(r'xyz', sentence))
    -False
    +
    >>> sentence = 'This is a sample string'
    +>>> bool(re.search(r'this', sentence, flags=re.I))
    +True
    +>>> bool(re.search(r'xyz', sentence))
    +False
     

    re.findall()

    -
    >>> re.findall(r'\bs?pare?\b', 'par spar apparent spare part pare')
    -['par', 'spar', 'spare', 'pare']
    ->>> re.findall(r'\b0*[1-9]\d{2,}\b', '0501 035 154 12 26 98234')
    -['0501', '154', '98234']
    +
    >>> re.findall(r'\bs?pare?\b', 'par spar apparent spare part pare')
    +['par', 'spar', 'spare', 'pare']
    +>>> re.findall(r'\b0*[1-9]\d{2,}\b', '0501 035 154 12 26 98234')
    +['0501', '154', '98234']
     

    re.finditer()

    -
    >>> m_iter = re.finditer(r'[0-9]+', '45 349 651 593 4 204')
    ->>> [m[0] for m in m_iter if int(m[0]) < 350]
    -['45', '349', '4', '204']
    +
    >>> m_iter = re.finditer(r'[0-9]+', '45 349 651 593 4 204')
    +>>> [m[0] for m in m_iter if int(m[0]) < 350]
    +['45', '349', '4', '204']
     

    re.split()

    -
    >>> re.split(r'\d+', 'Sample123string42with777numbers')
    -['Sample', 'string', 'with', 'numbers']
    +
    >>> re.split(r'\d+', 'Sample123string42with777numbers')
    +['Sample', 'string', 'with', 'numbers']
     

    re.sub()

    -
    >>> ip_lines = "catapults\nconcatenate\ncat"
    ->>> print(re.sub(r'^', r'* ', ip_lines, flags=re.M))
    -* catapults
    -* concatenate
    -* cat
    +
    >>> ip_lines = "catapults\nconcatenate\ncat"
    +>>> print(re.sub(r'^', r'* ', ip_lines, flags=re.M))
    +* catapults
    +* concatenate
    +* cat
     

    re.compile()

    -
    >>> pet = re.compile(r'dog')
    ->>> type(pet)
    -<class '_sre.SRE_Pattern'>
    ->>> bool(pet.search('They bought a dog'))
    -True
    ->>> bool(pet.search('A cat crossed their path'))
    -False
    +
    >>> pet = re.compile(r'dog')
    +>>> type(pet)
    +<class '_sre.SRE_Pattern'>
    +>>> bool(pet.search('They bought a dog'))
    +True
    +>>> bool(pet.search('A cat crossed their path'))
    +False
     

    函数

    @@ -1867,75 +1867,75 @@
    :---
    re.Ire.IGNORECASE忽略大小写
    re.Mre.MULTILINE多行
    re.Lre.LOCALE使 \w\b\s locale 依赖
    re.Sre.DOTALL点匹配所有 (包括换行符)
    re.Ure.UNICODE使 \w\b\d\s unicode 依赖
    re.Xre.VERBOSE可读风格

    JavaScript 中的正则表达式

    test()

    -
    let textA = 'I like APPles very much';
    -let textB = 'I like APPles';
    -let regex = /apples$/i
    - 
    -// Output: false
    -console.log(regex.test(textA));
    - 
    -// Output: true
    -console.log(regex.test(textB));
    +
    let textA = 'I like APPles very much';
    +let textB = 'I like APPles';
    +let regex = /apples$/i
    + 
    +// Output: false
    +console.log(regex.test(textA));
    + 
    +// Output: true
    +console.log(regex.test(textB));
     
    -
    let text = 'I like APPles very much';
    -let regexA = /apples/;
    -let regexB = /apples/i;
    - 
    -// Output: -1
    -console.log(text.search(regexA));
    - 
    -// Output: 7
    -console.log(text.search(regexB));
    +
    let text = 'I like APPles very much';
    +let regexA = /apples/;
    +let regexB = /apples/i;
    + 
    +// Output: -1
    +console.log(text.search(regexA));
    + 
    +// Output: 7
    +console.log(text.search(regexB));
     

    exec()

    -
    let text = 'Do you like apples?';
    -let regex= /apples/;
    - 
    -// Output: apples
    -console.log(regex.exec(text)[0]);
    - 
    -// Output: Do you like apples?
    -console.log(regex.exec(text).input);
    +
    let text = 'Do you like apples?';
    +let regex= /apples/;
    + 
    +// Output: apples
    +console.log(regex.exec(text)[0]);
    + 
    +// Output: Do you like apples?
    +console.log(regex.exec(text).input);
     

    match()

    -
    let text = 'Here are apples and apPleS';
    -let regex = /apples/gi;
    - 
    -// Output: [ "apples", "apPleS" ]
    -console.log(text.match(regex));
    +
    let text = 'Here are apples and apPleS';
    +let regex = /apples/gi;
    + 
    +// Output: [ "apples", "apPleS" ]
    +console.log(text.match(regex));
     

    split()

    -
    let text = 'This 593 string will be brok294en at places where d1gits are.';
    -let regex = /\d+/g
    - 
    -// Output: [ "This ", " string will be brok", "en at places where d", "gits are." ] 
    -console.log(text.split(regex))
    +
    let text = 'This 593 string will be brok294en at places where d1gits are.';
    +let regex = /\d+/g
    + 
    +// Output: [ "This ", " string will be brok", "en at places where d", "gits are." ] 
    +console.log(text.split(regex))
     

    matchAll()

    -
    let regex = /t(e)(st(\d?))/g;
    -let text = 'test1test2';
    -let array = [...text.matchAll(regex)];
    -// Output: ["test1", "e", "st1", "1"]
    -console.log(array[0]);
    -// Output: ["test2", "e", "st2", "2"]
    -console.log(array[1]);
    +
    let regex = /t(e)(st(\d?))/g;
    +let text = 'test1test2';
    +let array = [...text.matchAll(regex)];
    +// Output: ["test1", "e", "st1", "1"]
    +console.log(array[0]);
    +// Output: ["test2", "e", "st2", "2"]
    +console.log(array[1]);
     

    replace()

    -
    let text = 'Do you like aPPles?';
    -let regex = /apples/i
    - 
    -// Output: Do you like mangoes?
    -let result = text.replace(regex, 'mangoes');
    -console.log(result);
    +
    let text = 'Do you like aPPles?';
    +let regex = /apples/i
    + 
    +// Output: Do you like mangoes?
    +let result = text.replace(regex, 'mangoes');
    +console.log(result);
     

    replaceAll()

    -
    let regex = /apples/gi;
    -let text = 'Here are apples and apPleS';
    -// Output: Here are mangoes and mangoes
    -let result = text.replaceAll(regex, "mangoes");
    -console.log(result);
    +
    let regex = /apples/gi;
    +let text = 'Here are apples and apPleS';
    +// Output: Here are mangoes and mangoes
    +let result = text.replaceAll(regex, "mangoes");
    +console.log(result);
     

    PHP中的正则表达式

    @@ -1976,62 +1976,62 @@
    :--
    preg_match()执行正则表达式匹配
    preg_match_all()执行全局正则表达式匹配
    preg_replace_callback()使用回调执行正则表达式搜索和替换
    preg_replace()执行正则表达式搜索和替换
    preg_split()按正则表达式模式拆分字符串
    preg_grep()返回与模式匹配的数组条目

    preg_replace

    -
    $str = "Visit Microsoft!";
    -$regex = "/microsoft/i";
    -// Output: Visit QuickRef!
    -echo preg_replace($regex, "QuickRef", $str); 
    +
    $str = "Visit Microsoft!";
    +$regex = "/microsoft/i";
    +// Output: Visit QuickRef!
    +echo preg_replace($regex, "QuickRef", $str); 
     

    preg_match

    -
    $str = "Visit QuickRef";
    -$regex = "#quickref#i";
    -// Output: 1
    -echo preg_match($regex, $str);
    +
    $str = "Visit QuickRef";
    +$regex = "#quickref#i";
    +// Output: 1
    +echo preg_match($regex, $str);
     

    preg_matchall

    -
    $regex = "/[a-zA-Z]+ (\d+)/";
    -$input_str = "June 24, August 13, and December 30";
    -if (preg_match_all($regex, $input_str, $matches_out)) {
    -    // Output: 2
    -    echo count($matches_out);
    -    // Output: 3
    -    echo count($matches_out[0]);
    -    // Output: Array("June 24", "August 13", "December 30")
    -    print_r($matches_out[0]);
    -    // Output: Array("24", "13", "30")
    -    print_r($matches_out[1]);
    -}
    +
    $regex = "/[a-zA-Z]+ (\d+)/";
    +$input_str = "June 24, August 13, and December 30";
    +if (preg_match_all($regex, $input_str, $matches_out)) {
    +    // Output: 2
    +    echo count($matches_out);
    +    // Output: 3
    +    echo count($matches_out[0]);
    +    // Output: Array("June 24", "August 13", "December 30")
    +    print_r($matches_out[0]);
    +    // Output: Array("24", "13", "30")
    +    print_r($matches_out[1]);
    +}
     

    preg_grep

    -
    $arr = ["Jane", "jane", "Joan", "JANE"];
    -$regex = "/Jane/";
    -// Output: Jane
    -echo preg_grep($regex, $arr);
    +
    $arr = ["Jane", "jane", "Joan", "JANE"];
    +$regex = "/Jane/";
    +// Output: Jane
    +echo preg_grep($regex, $arr);
     

    preg_split

    -
    $str = "Jane\tKate\nLucy Marion";
    -$regex = "@\s@";
    -// Output: Array("Jane", "Kate", "Lucy", "Marion")
    -print_r(preg_split($regex, $str));
    +
    $str = "Jane\tKate\nLucy Marion";
    +$regex = "@\s@";
    +// Output: Array("Jane", "Kate", "Lucy", "Marion")
    +print_r(preg_split($regex, $str));
     

    Java 中的正则表达式

    风格

    第一种方式

    -
    Pattern p = Pattern.compile(".s", Pattern.CASE_INSENSITIVE);
    -Matcher m = p.matcher("aS");  
    -boolean s1 = m.matches();  
    -System.out.println(s1);   // Outputs: true
    +
    Pattern p = Pattern.compile(".s", Pattern.CASE_INSENSITIVE);
    +Matcher m = p.matcher("aS");  
    +boolean s1 = m.matches();  
    +System.out.println(s1);   // Outputs: true
     

    第二种方式

    -
    boolean s2 = Pattern.compile("[0-9]+").matcher("123").matches();  
    -System.out.println(s2);   // Outputs: true
    +
    boolean s2 = Pattern.compile("[0-9]+").matcher("123").matches();  
    +System.out.println(s2);   // Outputs: true
     

    第三种方式

    -
    boolean s3 = Pattern.matches(".s", "XXXX");  
    -System.out.println(s3);   // Outputs: false
    +
    boolean s3 = Pattern.matches(".s", "XXXX");  
    +System.out.println(s3);   // Outputs: false
     

    模式字段

    @@ -2098,24 +2098,24 @@

    例子

    替换句子:

    -
    String regex = "[A-Z\n]{5}$";
    -String str = "I like APP\nLE";
    -Pattern p = Pattern.compile(regex, Pattern.MULTILINE);
    -Matcher m = p.matcher(str);
    -// Outputs: I like Apple!
    -System.out.println(m.replaceAll("pple!"));
    +
    String regex = "[A-Z\n]{5}$";
    +String str = "I like APP\nLE";
    +Pattern p = Pattern.compile(regex, Pattern.MULTILINE);
    +Matcher m = p.matcher(str);
    +// Outputs: I like Apple!
    +System.out.println(m.replaceAll("pple!"));
     

    所有匹配的数组:

    -
    String str = "She sells seashells by the Seashore";
    -String regex = "\\w*se\\w*";
    -Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
    -Matcher m = p.matcher(str);
    -List<String> matches = new ArrayList<>();
    -while (m.find()) {
    -    matches.add(m.group());
    -}
    -// Outputs: [sells, seashells, Seashore]
    -System.out.println(matches);
    +
    String str = "She sells seashells by the Seashore";
    +String regex = "\\w*se\\w*";
    +Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
    +Matcher m = p.matcher(str);
    +List<String> matches = new ArrayList<>();
    +while (m.find()) {
    +    matches.add(m.group());
    +}
    +// Outputs: [sells, seashells, Seashore]
    +System.out.println(matches);
     

    MySQL中的正则表达式

    @@ -2151,62 +2151,62 @@
    函数名称说明
    REGEXP 字符串是否匹配正则表达式
    REGEXP_INSTR() 匹配正则表达式的子字符串的起始索引
    (注意:仅限 MySQL 8.0+)
    REGEXP_LIKE() 字符串是否匹配正则表达式
    (注意:仅 MySQL 8.0+)
    REGEXP_REPLACE()替换匹配正则表达式的子字符串
    (注意:仅限 MySQL 8.0+)
    REGEXP_SUBSTR() 返回匹配正则表达式的子字符串
    (注意:仅 MySQL 8.0+)

    REGEXP

    -
    expr REGEXP pat 
    +
    expr REGEXP pat 
     

    Examples

    -
    mysql> SELECT 'abc' REGEXP '^[a-d]';
    -1
    -mysql> SELECT name FROM cities WHERE name REGEXP '^A';
    -mysql> SELECT name FROM cities WHERE name NOT REGEXP '^A';
    -mysql> SELECT name FROM cities WHERE name REGEXP 'A|B|R';
    -mysql> SELECT 'a' REGEXP 'A', 'a' REGEXP BINARY 'A';
    -1   0
    +
    mysql> SELECT 'abc' REGEXP '^[a-d]';
    +1
    +mysql> SELECT name FROM cities WHERE name REGEXP '^A';
    +mysql> SELECT name FROM cities WHERE name NOT REGEXP '^A';
    +mysql> SELECT name FROM cities WHERE name REGEXP 'A|B|R';
    +mysql> SELECT 'a' REGEXP 'A', 'a' REGEXP BINARY 'A';
    +1   0
     

    REGEXP_REPLACE

    -
    REGEXP_REPLACE(expr, pat, repl[, pos[, occurrence[, match_type]]])
    +
    REGEXP_REPLACE(expr, pat, repl[, pos[, occurrence[, match_type]]])
     

    例子

    -
    mysql> SELECT REGEXP_REPLACE('a b c', 'b', 'X');
    -a X c
    -mysql> SELECT REGEXP_REPLACE('abc ghi', '[a-z]+', 'X', 1, 2);
    -abc X
    +
    mysql> SELECT REGEXP_REPLACE('a b c', 'b', 'X');
    +a X c
    +mysql> SELECT REGEXP_REPLACE('abc ghi', '[a-z]+', 'X', 1, 2);
    +abc X
     

    REGEXP_SUBSTR

    -
    REGEXP_SUBSTR(expr, pat[, pos[, occurrence[, match_type]]])
    +
    REGEXP_SUBSTR(expr, pat[, pos[, occurrence[, match_type]]])
     

    例子

    -
    mysql> SELECT REGEXP_SUBSTR('abc def ghi', '[a-z]+');
    -abc
    -mysql> SELECT REGEXP_SUBSTR('abc def ghi', '[a-z]+', 1, 3);
    -ghi
    +
    mysql> SELECT REGEXP_SUBSTR('abc def ghi', '[a-z]+');
    +abc
    +mysql> SELECT REGEXP_SUBSTR('abc def ghi', '[a-z]+', 1, 3);
    +ghi
     

    REGEXP_LIKE

    -
    REGEXP_LIKE(expr, pat[, match_type])
    +
    REGEXP_LIKE(expr, pat[, match_type])
     

    例子

    -
    mysql> SELECT regexp_like('aba', 'b+')
    -1
    -mysql> SELECT regexp_like('aba', 'b{2}')
    -0
    -mysql> # i: case-insensitive
    -mysql> SELECT regexp_like('Abba', 'ABBA', 'i');
    -1
    -mysql> # m: multi-line
    -mysql> SELECT regexp_like('a\nb\nc', '^b$', 'm');
    -1
    +
    mysql> SELECT regexp_like('aba', 'b+')
    +1
    +mysql> SELECT regexp_like('aba', 'b{2}')
    +0
    +mysql> # i: case-insensitive
    +mysql> SELECT regexp_like('Abba', 'ABBA', 'i');
    +1
    +mysql> # m: multi-line
    +mysql> SELECT regexp_like('a\nb\nc', '^b$', 'm');
    +1
     

    REGEXP_INSTR

    -
    REGEXP_INSTR(expr, pat[, pos[, occurrence[, return_option[, match_type]]]])
    +
    REGEXP_INSTR(expr, pat[, pos[, occurrence[, return_option[, match_type]]]])
     

    例子

    -
    mysql> SELECT regexp_instr('aa aaa aaaa', 'a{3}');
    -2
    -mysql> SELECT regexp_instr('abba', 'b{2}', 2);
    -2
    -mysql> SELECT regexp_instr('abbabba', 'b{2}', 1, 2);
    -5
    -mysql> SELECT regexp_instr('abbabba', 'b{2}', 1, 3, 1);
    -7
    +
    mysql> SELECT regexp_instr('aa aaa aaaa', 'a{3}');
    +2
    +mysql> SELECT regexp_instr('abba', 'b{2}', 2);
    +2
    +mysql> SELECT regexp_instr('abbabba', 'b{2}', 1, 2);
    +5
    +mysql> SELECT regexp_instr('abbabba', 'b{2}', 1, 3, 1);
    +7
     

    也可以看看

      diff --git a/docs/sed.html b/docs/sed.html index 40a1e603..7c14c7da 100644 --- a/docs/sed.html +++ b/docs/sed.html @@ -38,12 +38,12 @@

    入门

    Sed 用法

    语法

    -
    $ sed [options] command [input-file]
    +
    $ sed [options] command [input-file]
     

    带管道

    -
    $ cat report.txt | sed 's/Nick/John/g'
    +
    $ cat report.txt | sed 's/Nick/John/g'
     
    -
    $ echo '123abc' | sed 's/[0-9]+//g'
    +
    $ echo '123abc' | sed 's/[0-9]+//g'
     

    选项示例

    @@ -85,22 +85,22 @@
    参数示例描述
    -ised -ibak 's/On/Off/' php.ini直接备份和修改输入文件
    -Esed -E 's/[0-9]+//g' input-file使用扩展正则表达式
    -nsed -n '3 p' config.conf禁止默认图案空间打印
    -fsed -f script.sed config.conf执行 sed 脚本文件
    -esed -e 'command1' -e 'command2' input-file执行多个 sed 命令

    多个命令

    -
    $ echo "hello world" | sed -e 's/h/H/g' -e 's/w/W/g'
    -Hello World
    +
    $ echo "hello world" | sed -e 's/h/H/g' -e 's/w/W/g'
    +Hello World
     

    使用 -e 执行多个 sed 命令

    Sed 脚本

    -
    $ echo 's/h/H/g' >> hello.sed
    -$ echo 's/w/W/g' >> hello.sed
    -$ echo "hello world" | sed -f hello.sed
    -Hello World
    +
    $ echo 's/h/H/g' >> hello.sed
    +$ echo 's/w/W/g' >> hello.sed
    +$ echo "hello world" | sed -f hello.sed
    +Hello World
     

    使用 -f 执行 sed 脚本文件

    Examples

    -
    $ sed 's/old/new/g' file.txt
    -$ sed 's/old/new/g' file.txt > new.txt
    -$ sed 's/old/new/g' -i file.txt
    -$ sed 's/old/new/g' -i.backup file.txt
    +
    $ sed 's/old/new/g' file.txt
    +$ sed 's/old/new/g' file.txt > new.txt
    +$ sed 's/old/new/g' -i file.txt
    +$ sed 's/old/new/g' -i.backup file.txt
     

    Sed 命令

    命令

    @@ -183,7 +183,7 @@
    CommandDescription
    n打印模式空间,空模式空间,读取下一行
    x用保持空间交换模式空间
    h复制模式空间以保持空间
    H追加模式空间以保持空间
    g将保持空间复制到模式空间
    G将保持空间附加到模式空间

    Flags

    -
    $ sed 's/old/new/[flags]' [input-file]
    +
    $ sed 's/old/new/[flags]' [input-file]
     

    @@ -282,107 +282,107 @@

    替换文本

    替换所有出现的字符串

    -
    $ sed 's/old/new/g' file.txt
    +
    $ sed 's/old/new/g' file.txt
     

    仅替换第 n 次出现的字符串

    -
    $ sed 's/old/new/2' file.txt
    +
    $ sed 's/old/new/2' file.txt
     

    仅在第 5 行替换替换字符串

    -
    $ sed '5 s/old/new/' file.txt
    +
    $ sed '5 s/old/new/' file.txt
     

    将“world”替换为“universe”,但前提是该行以“hello”开头

    -
    $ sed '/hello/s/world/universe/' file.txt
    +
    $ sed '/hello/s/world/universe/' file.txt
     

    从每行的末尾删除“\”

    -
    $ sed 's/\\$//' file.txt
    +
    $ sed 's/\\$//' file.txt
     

    删除每行开头的所有空格

    -
    $ sed 's/^\s*//' file.txt
    +
    $ sed 's/^\s*//' file.txt
     

    删除评论。 即使是那些在行尾的

    -
    $ sed 's/#.*$//' file.txt
    +
    $ sed 's/#.*$//' file.txt
     

    搜索文本

    搜索字符串并仅打印匹配的行

    -
    $ sed -n '/hello/p' file.txt
    +
    $ sed -n '/hello/p' file.txt
     

    不区分大小写的搜索

    -
    $ sed -n '/hello/Ip' file.txt
    +
    $ sed -n '/hello/Ip' file.txt
     

    搜索字符串,但仅输出不匹配的行

    -
    $ sed -n '/hello/!p' file.txt
    +
    $ sed -n '/hello/!p' file.txt
     

    追加行

    在第 2 行之后追加一行

    -
    $ sed '2a Text after line 2' file.txt
    +
    $ sed '2a Text after line 2' file.txt
     

    在文件末尾追加一行

    -
    $ sed '$a THE END!' file.txt
    +
    $ sed '$a THE END!' file.txt
     

    从第 3 行开始,每 3 行后追加一行

    -
    $ sed '3~3a Some text' file.txt
    +
    $ sed '3~3a Some text' file.txt
     

    编号

    文件的数字行(简单的左对齐)

    -
    $ sed = file.txt | sed 'N;s/\n/\t/'
    +
    $ sed = file.txt | sed 'N;s/\n/\t/'
     

    文件的数字行(数字在左,右对齐)

    -
    $ sed = file.txt | sed 'N; s/^/   /; s/ *\(.\{6,\}\)\n/\1  /'
    +
    $ sed = file.txt | sed 'N; s/^/   /; s/ *\(.\{6,\}\)\n/\1  /'
     

    文件的数字行,但如果行不为空,则仅打印数字

    -
    $ sed '/./=' file.txt | sed '/./N; s/\n/ /'
    +
    $ sed '/./=' file.txt | sed '/./N; s/\n/ /'
     

    计算行数(模拟“wc -l”)

    -
    $ sed -n '$='
    +
    $ sed -n '$='
     

    前置行

    在第 5 行之前插入文本

    -
    $ sed '5i line number five' file.txt
    +
    $ sed '5i line number five' file.txt
     

    在包含“hello”的每一行之前插入“示例:”

    -
    $ sed '/hello/i Example: ' file.txt
    +
    $ sed '/hello/i Example: ' file.txt
     

    删除行

    删除文件中的第 5-7 行

    -
    $ sed '5,7d' file.txt
    +
    $ sed '5,7d' file.txt
     

    删除从第 3 行开始的每 2 行

    -
    $ sed '3~2d' file.txt
    +
    $ sed '3~2d' file.txt
     

    删除文件的最后一行

    -
    $ sed '$d' file.txt
    +
    $ sed '$d' file.txt
     

    删除以“Hello”开头的行

    -
    $ sed '/^Hello/d' file.txt
    +
    $ sed '/^Hello/d' file.txt
     

    删除所有空行

    -
    $ sed '/^$/d' file.txt
    +
    $ sed '/^$/d' file.txt
     

    删除以“#”开头的行

    -
    $ sed '/^#/d' file.txt
    +
    $ sed '/^#/d' file.txt
     

    文件间距

    双倍行距

    -
    $ sed G
    +
    $ sed G
     

    删除所有空行和双空格

    -
    $ sed '/^$/d;G'
    +
    $ sed '/^$/d;G'
     

    三倍空间文件

    -
    $ sed 'G;G'
    +
    $ sed 'G;G'
     

    撤消双倍行距

    -
    $ sed 'n;d'
    +
    $ sed 'n;d'
     

    在匹配“正则表达式”的行上方插入一个空行

    -
    $ sed '/regex/{x;p;x;}'
    +
    $ sed '/regex/{x;p;x;}'
     

    在匹配“正则表达式”的行下方插入一个空行

    -
    $ sed '/regex/G'
    +
    $ sed '/regex/G'
     

    在匹配“正则表达式”的行周围插入一个空行

    -
    $ sed '/regex/{x;p;x;G;}'
    +
    $ sed '/regex/{x;p;x;G;}'
     

    另见

      diff --git a/docs/semver.html b/docs/semver.html index b31aef90..154602a6 100644 --- a/docs/semver.html +++ b/docs/semver.html @@ -67,11 +67,11 @@
      --
      主版本号(MAJOR)当你做了不兼容的 API 修改
      次版本号(MINOR)当你做了向下兼容的功能性新增
      修订号(PATCH)当你做了向下兼容的问题修正

    简单范围

    -
      1.2.3
    - =1.2.3
    - >1.2.3
    - <1.2.3
    ->=1.2.3
    +
      1.2.3
    + =1.2.3
    + >1.2.3
    + <1.2.3
    +>=1.2.3
     

    请注意,后缀版本(1.2.3-rc1)不匹配。

    范围

    @@ -229,7 +229,7 @@
    范围描述
    >=0.14 <16和 (空格分隔)
    0.14.x || 15.x.x或 (双竖线分隔)

    预发布

    -
    1.2.3-prerelease+build
    +
    1.2.3-prerelease+build
     

    解释

    diff --git a/docs/ssh.html b/docs/ssh.html index 551d772d..31beb400 100644 --- a/docs/ssh.html +++ b/docs/ssh.html @@ -39,45 +39,45 @@

    入门

    连接

    连接到服务器(默认端口 22)

    -
    $ ssh root@192.168.1.5
    +
    $ ssh root@192.168.1.5
     

    在特定端口上连接

    -
    $ ssh root@192.168.1.5 -p 6222
    +
    $ ssh root@192.168.1.5 -p 6222
     

    通过 pem 文件连接(0400 权限)

    -
    $ ssh -i /path/file.pem root@192.168.1.5
    +
    $ ssh -i /path/file.pem root@192.168.1.5
     

    请参阅:SSH 权限

    执行

    执行远程命令

    -
    $ ssh root@192.168.1.5 'ls -l'
    +
    $ ssh root@192.168.1.5 'ls -l'
     

    调用本地脚本

    -
    $ ssh root@192.168.1.5 bash < script.sh
    +
    $ ssh root@192.168.1.5 bash < script.sh
     

    从服务器压缩和下载

    -
    $ ssh root@192.168.1.5 "tar cvzf - ~/source" > output.tgz
    +
    $ ssh root@192.168.1.5 "tar cvzf - ~/source" > output.tgz
     

    SCP

    从远程复制到本地

    -
    $ scp user@server:/dir/file.ext dest/
    +
    $ scp user@server:/dir/file.ext dest/
     

    两台服务器之间的副本

    -
    $ scp user@server:/file user@server:/dir
    +
    $ scp user@server:/file user@server:/dir
     

    从本地复制到远程

    -
    $ scp dest/file.ext user@server:/dir
    +
    $ scp dest/file.ext user@server:/dir
     

    复制整个文件夹

    -
    $ scp -r user@server:/dir dest/
    +
    $ scp -r user@server:/dir dest/
     

    复制文件夹中的所有文件

    -
    $ scp user@server:/dir/* dest/
    +
    $ scp user@server:/dir/* dest/
     

    从服务器文件夹复制到当前文件夹

    -
    $ scp user@server:/dir/* .
    +
    $ scp user@server:/dir/* .
     

    配置位置

    @@ -150,41 +150,41 @@
    选项说明
    scp -r递归复制整个目录
    scp -C压缩数据
    scp -v打印详细信息
    scp -P 8080使用特定端口
    scp -B批处理模式_(防止密码)_
    scp -p保留时间和模式

    配置示例

    -
    Host server1 
    -    HostName 192.168.1.5
    -    User root
    -    Port 22
    -    IdentityFile ~/.ssh/server1.key
    +
    Host server1 
    +    HostName 192.168.1.5
    +    User root
    +    Port 22
    +    IdentityFile ~/.ssh/server1.key
     

    通过别名启动

    -
    $ ssh server1
    +
    $ ssh server1
     

    请参阅:完整 配置选项

    ProxyJump

    -
    $ ssh -J proxy_host1 remote_host2
    +
    $ ssh -J proxy_host1 remote_host2
     
    -
    $ ssh -J user@proxy_host1 user@remote_host2
    +
    $ ssh -J user@proxy_host1 user@remote_host2
     

    多次跳跃

    -
    $ ssh -J user@proxy_host1:port1,user@proxy_host2:port2 user@remote_host3
    +
    $ ssh -J user@proxy_host1:port1,user@proxy_host2:port2 user@remote_host3
     

    ssh-copy-id

    -
    $ ssh-copy-id user@server
    +
    $ ssh-copy-id user@server
     

    复制到别名服务器

    -
    $ ssh-copy-id server1
    +
    $ ssh-copy-id server1
     

    复制特定密钥

    -
    $ ssh-copy-id -i ~/.ssh/id_rsa.pub user@server
    +
    $ ssh-copy-id -i ~/.ssh/id_rsa.pub user@server
     

    SSH keygen

    ssh-keygen

    -
    $ ssh-keygen -t rsa -b 4096 -C "your@mail.com" 
    +
    $ ssh-keygen -t rsa -b 4096 -C "your@mail.com" 
     

    @@ -217,19 +217,19 @@

    产生

    以交互方式生成密钥

    -
    $ ssh-keygen
    +
    $ ssh-keygen
     

    指定文件名

    -
    $ ssh-keygen -f ~/.ssh/filename
    +
    $ ssh-keygen -f ~/.ssh/filename
     

    从私钥生成公钥

    -
    $ ssh-keygen -y -f private.key > public.pub
    +
    $ ssh-keygen -y -f private.key > public.pub
     

    更改评论

    -
    $ ssh-keygen -c -f ~/.ssh/id_rsa
    +
    $ ssh-keygen -c -f ~/.ssh/id_rsa
     

    更改私钥密码

    -
    $ ssh-keygen -p -f ~/.ssh/id_rsa
    +
    $ ssh-keygen -p -f ~/.ssh/id_rsa
     

    钥匙类型

      @@ -241,10 +241,10 @@

    known_hosts

    从 known_hosts 搜索

    -
    $ ssh-keygen -F <ip/hostname>
    +
    $ ssh-keygen -F <ip/hostname>
     

    从 known_hosts 中删除

    -
    $ ssh-keygen -R <ip/hostname>
    +
    $ ssh-keygen -R <ip/hostname>
     

    密钥格式

      diff --git a/docs/toml.html b/docs/toml.html index 7f17198b..aa2d8bb9 100644 --- a/docs/toml.html +++ b/docs/toml.html @@ -44,169 +44,169 @@
    • Learn X in Y minutes (learnxinyminutes.com)

    示例

    -
    bool = true
    -date = 2006-05-27T07:32:00Z
    -string = "hello"
    -number = 42
    -float = 3.14
    -scientificNotation = 1e+12
    +
    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
    +
    # A single line comment example
    +# block level comment example
    +# 注释行 1
    +# 注释行 2
    +# 注释行 3
     

    整数

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

    浮点数

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

    布尔值

    -
    bool1 = true
    -bool2 = false
    -boolMustBeLowercase = true
    +
    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
    +
    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."
    +
    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
    +
    [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 = [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"
    -]
    +
    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. 
    -"""
    +
    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*>'
    +
    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.
    -'''
    +
    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
    +
    [name]
    +foo = 1
    +bar = 2
     

    foobar 是名为name 的表中的键

    嵌套

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

    类数组

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

    ↓ 等效的 JSON

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

    点分隔

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

    ↓ 等效的 JSON

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

    多嵌套

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

    ↓ 等效的 JSON

    -
    {
    -	"foo" : {
    -		"bar" : {
    -			"baz" : {
    -				"bat" : "hi"
    -			}
    -		}
    -	}
    -}
    +
    {
    +	"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']
    +
    [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" }
    +
    name = { first = "Tom", last = "Preston-Werner" }
    +point = { x = 1, y = 2 }
    +animal = { type.name = "pug" }
     
    © 2022 Kenny Wang, All rights reserved.
    diff --git a/docs/typescript.html b/docs/typescript.html index 7de228df..047b67e8 100644 --- a/docs/typescript.html +++ b/docs/typescript.html @@ -44,112 +44,112 @@
  • TypeScript 官网
  • 内置类型基元

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

    常见的内置 JS 对象

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

    内置

    类型字面量

    Object:

    -
    { field: string }
    +
    { field: string }
     

    Function:

    -
    (arg: number) => string
    +
    (arg: number) => string
     

    Arrays:

    -
    string[] or Array<string>
    +
    string[] or Array<string>
     

    Tuple:

    -
    [string, number]
    +
    [string, number]
     

    避免

    -
    Object, String, Number, Boolean
    +
    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;
    -}
    +
    /** 可选择从现有接口或类型(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
    -}
    +
    interface APICall<Response> {
    +  data: Response
    +}
     

    用法

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

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

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

    重载

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

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

    类一致性

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

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

    Get & Set

    对象可以有自定义的 gettersetter

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

    用法

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

    通过合并扩展

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

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

    Type

    @@ -165,657 +165,657 @@

    使用实用程序类型构建

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

    原始类型

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

    主要用于文档

    对象字面类型

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

    联合类型

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

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

    交叉口类型

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

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

    从值类型

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

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

    从函数返回类型

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

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

    从模块类型

    -
    const data: import("./data").data
    +
    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;                  // 只读属性
    -}
    +
    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 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 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
    +
    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
    -}
    +
    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: ... }
    -}
    +
    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 (input instanceof Array) {
    +  input // number[]
    +}
     

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

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

    任务

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

    👇 使用 as const 缩小类型 👇

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

    跟踪相关变量

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

    重新分配更新类型

    -
    let data: string | number = ...
    -data // string | number
    -data = "Hello"
    -data // string
    +
    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
    +
    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 }
    +
    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
    -}
    +
    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!')
    -  }
    -}
    +
    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
    +
    const res = getResponse():
    +res // SuccessResponse | ErrorResponse
    +
    +// 断言函数改变当前作用域或抛出
    +assertResponse(res)
    +
    +res // SuccessResponse
     

    in 操作符

    -
    interface A {
    -  x: number;
    -}
    -interface B {
    -  y: string;
    -}
    -
    -function doStuff(q: A | B) {
    -  if ('x' in q) {
    -    // q: A
    -  } else {
    -    // q: B
    -  }
    -}
    +
    interface A {
    +  x: number;
    +}
    +interface B {
    +  y: string;
    +}
    +
    +function doStuff(q: A | B) {
    +  if ('x' in q) {
    +    // q: A
    +  } else {
    +    // q: B
    +  }
    +}
     

    操作符可以安全的检查一个对象上是否存在一个属性,它通常也被作为类型保护使用

    Class

    创建类实例

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

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

    private x 与 #private

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

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

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

    -
    class Bag { #item: any }
    +
    class Bag { #item: any }
     

    Class 上的 “this”

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

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

    类型和值

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

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

    所以,小心不要这样做:

    -
    class C implements 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 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")
    +
    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
    +
    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(): { ... } }
    +
    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>) { ... }
    -}
    +
    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;
    -  }
    -}
    +
    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
    +
    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>' 类型中是必需的。
    +
    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>;
    +
    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",
    -});
    +
    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>
    +
    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
    +
    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
    +
    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 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 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
    +
    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
    +
    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 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"
    +
    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"
    +
    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"
    +
    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"
    +
    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
    +
    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);
    +
    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
    +
    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);
    -}
    +
    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());
    +
    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

    @@ -828,143 +828,143 @@
  • JSX 规范
  • as 运算符

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

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

    基于值的元素

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

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

    内在的元素

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

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

    -
    declare namespace JSX {
    -  interface IntrinsicElements {
    -    [elemName: string]: any;
    -  }
    -}
    +
    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 />
    -);
    +
    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 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
    +
    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
     

    有效组件

    -
    declare namespace JSX {
    -  interface ElementClass {
    -    render: any;
    -  }
    -}
    -class MyComponent {
    -  render() {}
    -}
    -function MyFactoryFunction() {
    -  return { render: () => {} };
    -}
    -<MyComponent />;       // ✅ 有效类组件
    -<MyFactoryFunction />; // ✅ 有效函数组件
    +
    declare namespace JSX {
    +  interface ElementClass {
    +    render: any;
    +  }
    +}
    +class MyComponent {
    +  render() {}
    +}
    +function MyFactoryFunction() {
    +  return { render: () => {} };
    +}
    +<MyComponent />;       // ✅ 有效类组件
    +<MyFactoryFunction />; // ✅ 有效函数组件
     

    元素实例类型必须可以分配给 JSX.ElementClass,否则将导致错误。

    -
    class NotAValidComponent {}
    -function NotAValidFactoryFunction() {
    -  return {};
    -}
    -<NotAValidComponent />; // ❌ error
    -<NotAValidFactoryFunction />; // ❌ error
    +
    class NotAValidComponent {}
    +function NotAValidFactoryFunction() {
    +  return {};
    +}
    +<NotAValidComponent />; // ❌ error
    +<NotAValidFactoryFunction />; // ❌ error
     

    默认情况下,JSX.ElementClass 是 {},但可以对其进行扩展,以将 JSX 的使用限制为仅限于符合适当接口的类型。

    类组件

    -
    type Props = {
    -  header: React.ReactNode;
    -  body: React.ReactNode;
    -};
    -
    -class MyComponent extends React.Component<Props, {}> {
    -  render() {
    -    return (
    -      <div>
    -        {this.props.header}
    -        {this.props.body}
    -      </div>
    -    );
    -  }
    -}
    -
    -<MyComponent header={<h1>Header</h1>} body={<i>body</i>} />
    +
    type Props = {
    +  header: React.ReactNode;
    +  body: React.ReactNode;
    +};
    +
    +class MyComponent extends React.Component<Props, {}> {
    +  render() {
    +    return (
    +      <div>
    +        {this.props.header}
    +        {this.props.body}
    +      </div>
    +    );
    +  }
    +}
    +
    +<MyComponent header={<h1>Header</h1>} body={<i>body</i>} />
     

    泛型组件

    -
    // 一个泛型组件
    -type SelectProps<T> = { items: T[] };
    -class Select<T> extends React.Component<SelectProps<T>, any> {}
    -
    -// 使用
    -const Form = () => <Select<string> items={['a', 'b']} />;
    +
    // 一个泛型组件
    +type SelectProps<T> = { items: T[] };
    +class Select<T> extends React.Component<SelectProps<T>, any> {}
    +
    +// 使用
    +const Form = () => <Select<string> items={['a', 'b']} />;
     
    © 2022 Kenny Wang, All rights reserved.
    diff --git a/docs/vim.html b/docs/vim.html index d743cf09..6684df70 100644 --- a/docs/vim.html +++ b/docs/vim.html @@ -39,36 +39,36 @@

    入门

    运动图

    -
    ▼/▶ 光标   ▽/▷ 目标
    +
    ▼/▶ 光标   ▽/▷ 目标
     

    左右动作

    -
    ╭┈┈┈┈┈┈┈┈┈┈┈┈┈ |      
    -├┈┈┈┈┈┈┈┈┈┈┈┈┈ 0      $ ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈╮
    -┆  ╭┈┈┈┈┈┈┈┈┈┈ ^      fe ┈┈┈┈┈┈┈┈╮       ┆
    -┆  ┆  ╭┈┈┈┈┈┈┈ Fo     te ┈┈┈┈┈┈┈╮┆       ┆
    -┆  ┆  ┆╭┈┈┈┈┈┈ To     30| ┈┈┈╮  ┆┆       ┆
    -┆  ┆  ┆┆ ╭┈┈┈┈ ge     w ┈┈┈╮ ┆  ┆┆       ┆
    -┆  ┆  ┆┆ ┆ ╭┈┈ b      e ┈╮ ┆ ┆  ┆┆       ┆
    -┆  ┆  ┆┆ ┆ ┆  ╭h      l╮ ┆ ┆ ┆  ┆┆       ┆
    -▽  ▽  ▽▽ ▽ ▽  ▽▼      ▼▽ ▽ ▽ ▽  ▽▽       ▽
    -   echo "A cheatsheet from quickReference"
    +
    ╭┈┈┈┈┈┈┈┈┈┈┈┈┈ |      
    +├┈┈┈┈┈┈┈┈┈┈┈┈┈ 0      $ ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈╮
    +┆  ╭┈┈┈┈┈┈┈┈┈┈ ^      fe ┈┈┈┈┈┈┈┈╮       ┆
    +┆  ┆  ╭┈┈┈┈┈┈┈ Fo     te ┈┈┈┈┈┈┈╮┆       ┆
    +┆  ┆  ┆╭┈┈┈┈┈┈ To     30| ┈┈┈╮  ┆┆       ┆
    +┆  ┆  ┆┆ ╭┈┈┈┈ ge     w ┈┈┈╮ ┆  ┆┆       ┆
    +┆  ┆  ┆┆ ┆ ╭┈┈ b      e ┈╮ ┆ ┆  ┆┆       ┆
    +┆  ┆  ┆┆ ┆ ┆  ╭h      l╮ ┆ ┆ ┆  ┆┆       ┆
    +▽  ▽  ▽▽ ▽ ▽  ▽▼      ▼▽ ▽ ▽ ▽  ▽▽       ▽
    +   echo "A cheatsheet from quickReference"
     

    上下动作

    -
                      - SCREEN 1 START
    -   ╭┈┬┈┈┈┈┈┈┈┈┈▷  #!/usr/bin/python
    -   ┆ ┆     ╭┈┈┈▷      
    -   ┆ ┆     ┆      print("Hello")
    -   ┆ ┆     { } ▶  print("Vim")
    -   ┆ ┆       ┆    print("!")
    -   ┆ ┆       └┈▷     
    -   ┆ ┆ ╭┈┈┈┬┈┈┈▷  print("Welcome")
    -G gg H M L k j ▶  print("to")
    -┆        ┆   └┈▷  print("Quick Reference")
    -┆        ┆        print("/vim")
    -┆        ┆     
    -┆        ╰┈┈┈┈┈▷ 
    -┆                 - SCREEN 1 END
    -╰┈┈┈┈┈┈┈┈┈┈┈┈┈┈▷  print("SCREEN 2")
    +
                      - SCREEN 1 START
    +   ╭┈┬┈┈┈┈┈┈┈┈┈▷  #!/usr/bin/python
    +   ┆ ┆     ╭┈┈┈▷      
    +   ┆ ┆     ┆      print("Hello")
    +   ┆ ┆     { } ▶  print("Vim")
    +   ┆ ┆       ┆    print("!")
    +   ┆ ┆       └┈▷     
    +   ┆ ┆ ╭┈┈┈┬┈┈┈▷  print("Welcome")
    +G gg H M L k j ▶  print("to")
    +┆        ┆   └┈▷  print("Quick Reference")
    +┆        ┆        print("/vim")
    +┆        ┆     
    +┆        ╰┈┈┈┈┈▷ 
    +┆                 - SCREEN 1 END
    +╰┈┈┈┈┈┈┈┈┈┈┈┈┈┈▷  print("SCREEN 2")
     

    动作

    @@ -647,8 +647,8 @@
    组合说明
    dd删除当前行
    dj删除两行
    dw删除到下一个单词
    db删除到单词的开头
    dfa删除直到 a 字符
    d/hello删除直到 hello
    cc更改当前行,与 S 同义
    yy复制当前行
    >j缩进 2 行
    ggdG删除完整的文档
    gg=G缩进一个完整的文档
    ggyG复制整个文档

    计数

    -
    [数字] <运算符> <动作>
    -<运算符> [数字] <动作>
    +
    [数字] <运算符> <动作>
    +<运算符> [数字] <动作>
     

    @@ -1101,7 +1101,7 @@
    :--
    /foo向前搜索
    /foo\c向前搜索 (不区分大小写)
    ?foo向后搜索
    /\v\d+使用 regex 搜索
    n下一个匹配的搜索模式
    N上一场比赛
    *向前搜索当前单词
    #向后搜索当前单词

    更换行

    -
    :[range]s/{pattern}/{str}/[flags]
    +
    :[range]s/{pattern}/{str}/[flags]
     

    @@ -1139,7 +1139,7 @@
    :--
    :s/old/new先更换
    :s/old/new/g全部替换
    :s/\vold/new/g全部替换为 regex
    :s/old/new/gc全部替换_(确认)_
    :s/old/new/i先忽略大小写替换
    :2,6s/old/new/g2-6 行之间替换

    替换文件

    -
    :%s/{pattern}/{str}/[flags]
    +
    :%s/{pattern}/{str}/[flags]
     

    @@ -1222,7 +1222,7 @@
    :--
    %整个文件
    ’<,’>当前选择
    55
    5,105 行到第 10
    $最后一行
    2,$2 行到最后
    .当前行
    ,3接下来的 3
    -3,转发 3

    全局命令

    -
    :[range]g/{pattern}/[command]
    +
    :[range]g/{pattern}/[command]
     

    @@ -1264,7 +1264,7 @@
    :--
    :g/foo/d删除包含 foo 的行
    :g!/foo/d删除不包含 foo 的行
    :g/^\s*$/d删除所有空行
    :g/foo/t$将包含 foo 的行复制到 EOF
    :g/foo/m$将包含 foo 的行移动到 EOF
    :g/^/m0反转文件
    :g/^/t.复制每一行

    Inverse(逆) :g

    -
    :[range]v/{pattern}/[command]
    +
    :[range]v/{pattern}/[command]
     

    @@ -1353,33 +1353,33 @@
    :--
    & | \0替换为整个匹配的
    \1...\9替换为 0-9 组
    \u大写下一个字母
    \U后面的大写字符
    \l小写下一个字母
    \L后面的字符小写
    \e\u\U\l\L 的结尾
    \E\u\U\l\L 的结尾

    例子

    -
    :s/a\|b/xxx\0xxx/g               # 将 "a b"      修改为 "xxxaxxx xxxbxxx"
    -:s/test/\U& file/                # 将 "test"     修改为 "TEST FILE"
    -:s/\(test\)/\U\1\e file/         # 将 "test"     修改为 "TEST file"
    -:s/\v([abc])([efg])/\2\1/g       # 将 "af fa bg" 修改为 "fa fa gb"
    -:s/\v\w+/\u\0/g                  # 将 "bla bla"  修改为 "Bla Bla"
    -:s/\v([ab])|([cd])/\1x/g         # 将 "a b c d"  修改为 "ax bx x x"
    -:%s/.*/\L&/                      # 将 "HTML"     修改为 "html"
    -:s/\v<(.)(\w*)/\u\1\L\2/g        # 将单词的每个首字母大写
    -:%s/^\(.*\)\n\1/\1/              # 删除重复行
    -:%s/<\/\=\(\w\+\)\>/\U&/g        # 将 HTML 标记转换为大写
    -:g/^pattern/s/$/mytext           # 查找文本并将其附加到末尾
    -:g/pattern/norm! @i              # 在匹配行上运行宏
    -/^\(.*\)\(\r\?\n\1\)\+$          # 查看重复行
    -/\v^(.*)(\r?\n\1)+$              # 查看重复行(非常神奇)
    -:v/./,/./-j                      # 将空行压缩成空行
    -:g/<p1>/,/<p2>/d                 # 从 <p1> 到 <p2> 包含删除
    +
    :s/a\|b/xxx\0xxx/g               # 将 "a b"      修改为 "xxxaxxx xxxbxxx"
    +:s/test/\U& file/                # 将 "test"     修改为 "TEST FILE"
    +:s/\(test\)/\U\1\e file/         # 将 "test"     修改为 "TEST file"
    +:s/\v([abc])([efg])/\2\1/g       # 将 "af fa bg" 修改为 "fa fa gb"
    +:s/\v\w+/\u\0/g                  # 将 "bla bla"  修改为 "Bla Bla"
    +:s/\v([ab])|([cd])/\1x/g         # 将 "a b c d"  修改为 "ax bx x x"
    +:%s/.*/\L&/                      # 将 "HTML"     修改为 "html"
    +:s/\v<(.)(\w*)/\u\1\L\2/g        # 将单词的每个首字母大写
    +:%s/^\(.*\)\n\1/\1/              # 删除重复行
    +:%s/<\/\=\(\w\+\)\>/\U&/g        # 将 HTML 标记转换为大写
    +:g/^pattern/s/$/mytext           # 查找文本并将其附加到末尾
    +:g/pattern/norm! @i              # 在匹配行上运行宏
    +/^\(.*\)\(\r\?\n\1\)\+$          # 查看重复行
    +/\v^(.*)(\r?\n\1)+$              # 查看重复行(非常神奇)
    +:v/./,/./-j                      # 将空行压缩成空行
    +:g/<p1>/,/<p2>/d                 # 从 <p1> 到 <p2> 包含删除
     

    Vimdiff

    用法

    -
    $ vimdiff file1 file2 [file3]
    -$ vim -d file1 file2 [file3]
    +
    $ vimdiff file1 file2 [file3]
    +$ vim -d file1 file2 [file3]
     

    编辑

    -
    :[range]diffget [bufspec]
    -:[range]diffput [bufspec]
    +
    :[range]diffget [bufspec]
    +:[range]diffput [bufspec]
     

    @@ -1913,66 +1913,66 @@

    技巧

    删除重复行

    -
    :sort | %!uniq -u
    +
    :sort | %!uniq -u
     

    对文件中的行进行编号

    -
    :%!cat -n
    +
    :%!cat -n
     

    将整个文档复制到剪贴板

    -
    :%w !pbcopy            # Mac OS X
    -:%w !xclip -i -sel c   # GNU/Linux
    -:%w !xsel -i -b        # GNU/Linux
    +
    :%w !pbcopy            # Mac OS X
    +:%w !xclip -i -sel c   # GNU/Linux
    +:%w !xsel -i -b        # GNU/Linux
     

    理解 Vim

    动词理解

    -
    d  # 表示删除delete
    -r  # 表示替换replace
    -c  # 表示修改change
    -y  # 表示复制yank
    -v  # 表示选取visual select
    +
    d  # 表示删除delete
    +r  # 表示替换replace
    +c  # 表示修改change
    +y  # 表示复制yank
    +v  # 表示选取visual select
     

    动词代表了我们打算对文本进行什么样的操作

    名词理解

    -
    w  # 表示一个单词word
    -s  # 表示一个句子sentence
    -p  # 表示一个段落paragraph
    -t  # 表示一个 HTML 标签tag
    +
    w  # 表示一个单词word
    +s  # 表示一个句子sentence
    +p  # 表示一个段落paragraph
    +t  # 表示一个 HTML 标签tag
     

    名词代表了我们即将处理的文本。引号或者各种括号所包含的文本称作一个文本块。

    介词理解

    -
    i  # 表示在...之内 inside
    -a  # 表示环绕... around
    -t  # 表示到...位置前 to
    -f  # 表示到...位置上 forward
    +
    i  # 表示在...之内 inside
    +a  # 表示环绕... around
    +t  # 表示到...位置前 to
    +f  # 表示到...位置上 forward
     

    介词界定了待编辑文本的范围或者位置。

    数词理解

    数词指定了待编辑文本对象的数量,从这个角度而言,数词也可以看作是一种介词。引入数词之后,文本编辑命令的语法就升级成了下面这样:

    -
    动词 介词/数词 名词
    +
    动词 介词/数词 名词
     

    下面是几个例子:

    -
    c3w  # 修改三个单词:change three words
    -d2w  # 删除两个单词:delete two words
    +
    c3w  # 修改三个单词:change three words
    +d2w  # 删除两个单词:delete two words
     

    另外,数词也可以修饰动词,表示将操作执行 n 次。于是,我们又有了下面的语法:

    -
    数词 动词 名词
    +
    数词 动词 名词
     

    示例

    -
    2dw # 两次删除单词(等价于删除两个单词): twice delete word
    -3x  # 三次删除字符(等价于删除三个字符): three times delete character
    +
    2dw # 两次删除单词(等价于删除两个单词): twice delete word
    +3x  # 三次删除字符(等价于删除三个字符): three times delete character
     

    组词为句理解

    有了这些基本的语言元素,我们就可以着手构造一些简单的命令了。文本编辑命令的基本语法如下:

    -
    动词 介词 名词
    +
    动词 介词 名词
     

    下面是一些例子

    -
    dip # 删除一个段落: delete inside paragraph
    -vis # 选取一个句子: visual select inside sentence
    -ciw # 修改一个单词: change inside word
    -caw # 修改一个单词: change around word
    -dtx # 删除文本直到字符“x”(不包括字符“x”): delete to x
    -dfx # 删除文本直到字符“x”(包括字符“x”): delete forward x
    +
    dip # 删除一个段落: delete inside paragraph
    +vis # 选取一个句子: visual select inside sentence
    +ciw # 修改一个单词: change inside word
    +caw # 修改一个单词: change around word
    +dtx # 删除文本直到字符“x”(不包括字符“x”): delete to x
    +dfx # 删除文本直到字符“x”(包括字符“x”): delete forward x
     

    另见

    diff --git a/docs/xpath.html b/docs/xpath.html index 2ea0b637..27fbc36c 100644 --- a/docs/xpath.html +++ b/docs/xpath.html @@ -49,10 +49,10 @@
  • XPath 是 W3C 推荐的
  • FirefoxChrome 控制台中测试:

    -
    $x('/html/body')
    -$x('//h1')
    -$x('//h1')[0].innerText
    -$x('//a[text()="XPath"]')[0].click()
    +
    $x('/html/body')
    +$x('//h1')
    +$x('//h1')[0].innerText
    +$x('//a[text()="XPath"]')[0].click()
     

    后代选择器

    @@ -476,88 +476,88 @@

    XPath Predicates(谓词)

    Predicates(谓词)

    -
    //div[true()]
    -//div[@class="head"]
    -//div[@class="head"][@id="top"]
    +
    //div[true()]
    +//div[@class="head"]
    +//div[@class="head"][@id="top"]
     

    仅当某些条件为真时才限制节点集。它们可以被链接起来。

    操作符

    -
    # 比较
    -//a[@id = "xyz"]
    -//a[@id != "xyz"]
    -//a[@price > 25]
    +
    # 比较
    +//a[@id = "xyz"]
    +//a[@id != "xyz"]
    +//a[@price > 25]
     
    -
    # 逻辑 (and/or)
    -//div[@id="head" and position()=2]
    -//div[(x and y) or not(z)]
    +
    # 逻辑 (and/or)
    +//div[@id="head" and position()=2]
    +//div[(x and y) or not(z)]
     

    使用节点

    -
    # 在函数内部使用它们
    -//ul[count(li) > 2]
    -//ul[count(li[@class='hide']) > 0]
    +
    # 在函数内部使用它们
    +//ul[count(li) > 2]
    +//ul[count(li[@class='hide']) > 0]
     
    -
    # 返回具有 `<li>` 子级的 `<ul>`
    -//ul[li]
    +
    # 返回具有 `<li>` 子级的 `<ul>`
    +//ul[li]
     

    您可以在谓词中使用节点。

    索引

    -
    //a[1]                # 第一个<a>
    -//a[last()]           # 最后一个<a>
    -//ol/li[2]            # 第二个<li>
    -//ol/li[position()=2] # 和上面一样
    -//ol/li[position()>1] #:not(:first-child)
    +
    //a[1]                # 第一个<a>
    +//a[last()]           # 最后一个<a>
    +//ol/li[2]            # 第二个<li>
    +//ol/li[position()=2] # 和上面一样
    +//ol/li[position()>1] #:not(:first-child)
     

    [] 与数字一起使用,或者使用 last()position()

    链接顺序

    -
    a[1][@href='/']
    -a[@href='/'][1]
    +
    a[1][@href='/']
    +a[@href='/'][1]
     

    顺序很重要,这两个是不同的。

    嵌套谓词

    -
    //section[.//h1[@id='hi']]
    +
    //section[.//h1[@id='hi']]
     

    如果它有一个具有 id='hi'<h1> 后代,则返回 <section>

    XPath 函数

    节点功能

    -
    name()            # //[starts-with(name(), 'h')]
    -text()            # //button[text()="Submit"]
    -                  # //button/text()
    -lang(str)
    -namespace-uri()
    +
    name()            # //[starts-with(name(), 'h')]
    +text()            # //button[text()="Submit"]
    +                  # //button/text()
    +lang(str)
    +namespace-uri()
     
    -
    count()           # //table[count(tr)=1]
    -position()        # //ol/li[position()=2]
    +
    count()           # //table[count(tr)=1]
    +position()        # //ol/li[position()=2]
     

    字符串函数

    -
    contains()        # font[contains(@class,"head")]
    -starts-with()     # font[starts-with(@class,"head")]
    -ends-with()       # font[ends-with(@class,"head")]
    +
    contains()        # font[contains(@class,"head")]
    +starts-with()     # font[starts-with(@class,"head")]
    +ends-with()       # font[ends-with(@class,"head")]
     
    -
    concat(x,y)
    -substring(str, start, len)
    -substring-before("01/02", "/")  #=> 01
    -substring-after("01/02", "/")   #=> 02
    -translate()
    -normalize-space()
    -string-length()
    +
    concat(x,y)
    +substring(str, start, len)
    +substring-before("01/02", "/")  #=> 01
    +substring-after("01/02", "/")   #=> 02
    +translate()
    +normalize-space()
    +string-length()
     

    布尔函数

    -
    not(expr)         # button[not(starts-with(text(),"Submit"))]
    +
    not(expr)         # button[not(starts-with(text(),"Submit"))]
     

    类型转换

    -
    string()
    -number()
    -boolean()
    +
    string()
    +number()
    +boolean()
     

    XPath Axes

    使用轴

    -
    //ul/li                       # ul > li
    -//ul/child::li                # ul > li (same)
    -//ul/following-sibling::li    # ul ~ li
    -//ul/descendant-or-self::li   # ul li
    -//ul/ancestor-or-self::li     # $('ul').closest('li')
    +
    //ul/li                       # ul > li
    +//ul/child::li                # ul > li (same)
    +//ul/following-sibling::li    # ul ~ li
    +//ul/descendant-or-self::li   # ul li
    +//ul/ancestor-or-self::li     # $('ul').closest('li')
     

    @@ -586,29 +586,29 @@
    //ul/child::li
    AxisStepAxisStep

    表达式的步骤由 / 分隔,通常用于选择子节点。 这并不总是正确的:您可以使用 :: 指定不同的“轴”。

    子轴

    -
    # 都一样
    -//ul/li/a
    -//child::ul/child::li/child::a
    +
    # 都一样
    +//ul/li/a
    +//child::ul/child::li/child::a
     

    child:: is the default axis. This makes //a/b/c work.

    -
    # 都一样
    -# 这是因为 `child::li` 是真实的
    -//ul[li]
    -//ul[child::li]
    +
    # 都一样
    +# 这是因为 `child::li` 是真实的
    +//ul[li]
    +//ul[child::li]
     
    -
    # 都一样
    -//ul[count(li) > 2]
    -//ul[count(child::li) > 2]
    +
    # 都一样
    +//ul[count(li) > 2]
    +//ul[count(child::li) > 2]
     

    后代或自我轴

    -
    # 都一样
    -//div//h4
    -//div/descendant-or-self::h4
    +
    # 都一样
    +//div//h4
    +//div/descendant-or-self::h4
     

    //descendant-or-self:: 轴的缩写。

    -
    # 都一样
    -//ul//[last()]
    -//ul/descendant-or-self::[last()]
    +
    # 都一样
    +//ul//[last()]
    +//ul/descendant-or-self::[last()]
     

    其他轴

    @@ -691,33 +691,33 @@

    您还可以使用其他轴。

    联合

    -
    //a | //span
    +
    //a | //span
     

    使用 | 连接两个表达式。

    XPath 更多示例

    示例

    -
    //*                 # 所有元素
    -count(//*)          # 计算所有元素
    -(//h1)[1]/text()    # 第一个 h1 标题的文本
    -//li[span]          # 找到一个 <li> 里面有一个 <span>
    -                    # ...扩展到 //li[child::span]
    -//ul/li/..          # 使用 .. 选择父级
    +
    //*                 # 所有元素
    +count(//*)          # 计算所有元素
    +(//h1)[1]/text()    # 第一个 h1 标题的文本
    +//li[span]          # 找到一个 <li> 里面有一个 <span>
    +                    # ...扩展到 //li[child::span]
    +//ul/li/..          # 使用 .. 选择父级
     

    查找(父)家长

    -
    //section[h1[@id='section-name']]
    +
    //section[h1[@id='section-name']]
     

    查找直接包含 h1#section-name<section>

    -
    //section[//h1[@id='section-name']]
    +
    //section[//h1[@id='section-name']]
     

    查找包含 h1#section-name<section>。 (与上面相同,但使用后代或自我而不是孩子)

    最近的

    -
    ./ancestor-or-self::[@class="box"]
    +
    ./ancestor-or-self::[@class="box"]
     

    jQuery$().closest('.box') 一样工作。

    属性

    -
    //item[@price > 2*@discount]
    +
    //item[@price > 2*@discount]
     

    查找 <item> 并检查其属性

    另见

    diff --git a/style/style.css b/style/style.css index 32d6e40c..f8a4d13e 100644 --- a/style/style.css +++ b/style/style.css @@ -763,6 +763,19 @@ body:not(.home) .h2wrap > h2 a::after { .token.italic { font-style: italic; } .token.entity { cursor: help; } +.highlight-line { + background-color: var(--color-neutral-muted); + display: block; +} +.code-line.line-number::before { + display: inline-block; + width: 1rem; + text-align: right; + margin-right: 16px; + margin-left: -8px; + color: var(--color-fg-subtle); + content: attr(line); +} /* 代码高亮 End */ .footer-wrap {