node

node

Node

Node 简介

基于 Chrome V8 引擎的 JavaScript 运行环境

  • Node 与 浏览器均存在互不拥有的 API
  • Node.js 中你可以控制环境即控制运行时的 JS 版本
  • Node.js 使用 CommonJS 模块系统,浏览器使用 ES Modules 标准

Node 内置 API

process 核心进程
fs
path
http

Node 第三方框架

express 构建 Web 应用
electron 构建桌面应用
restify 构建 API 接口项目
读写数据库
实用命令行工具

Node 简单命令

node -v 查看 Node 版本号

node -h 查看 Node 的命令帮助

node <filename|filepath> 执行给定文件名或路径的 js 文件

node 进入 node 交互运行模式

终端快捷键
↑ 自动定位至上一条命令
TAB 自动补全路径
ESC 快速清空当前输入命令
cls 清空终端

process 模块

node 内置模块
隐式导入

process.exit(<exitCode>) 关闭正在执行的 node 进程

process.exitCode 规定 node 进程的退出码

process.env 读取 node 进程启动时设置的所有环境变量

fs 模块

node 内置模块

fs.open(<filepath>, <open-mode>, (<err>, <fd>) => {}) 获取文件描述符(?)

fs.readFile(<filepath>, (<err>, <stats>) => {}) 读取文件属性

stats.isFile()stats.isDirectory() 判断文件是否目录或文件
stats.size 获取文件的大小

fs.readFile(<filepath>, [options], (<err>, <data>) => {}) 读取文件内容

会将文件的全部内容读取至内存中,对于大文件使用流更好

fs.writeFile(<filepath>, data,[options], (<err>) => {}) 写文件内容

仅在将全部内容写入文件才会结束执行,对于数据量较大的使用流更好

以上函数均有sync后缀的同步版本函数

在读取文件时,存在相对路径 ./ ../,运行时可能会存在问题,一般推荐使用 path 模块动态拼接文件完整路径(如 __dirname + '/<filename>')或使用绝对路径

__dirname 脚本文件当前的目录路径
D:\程序\前端学习new\Node-eg
__filename 脚本文件当前的绝对路径
D:\程序\前端学习new\Node-eg\index.js

path 模块

node 内置模块

path.join([...paths]) 将多个路径片段拼接为完整的路径字符串

path.basename(<filepath>) 获取文件名部分
path.basename(<filepath>, path.extname(<filepath>)) 获取文件名不含扩展名部分

path.dirname(<filepath>) 获取文件的父文件夹部分

path.extname(<filepath>) 获取文件扩展名部分

path.resolve() 获得相对路径的绝对路径计算
可以在第一个参数的基础上指定路径,以使第二个参数附加第一个参数

需要注意的是,path模块方法仅做单纯的计算而不会主动判断路径的存在与否

http 模块

node 内置模块

基于js语言创建本地服务器

  • IP 地址
    ip 地址是互联网上各计算机的唯一地址
    192.169.1.1
    有 ipv4 与 ipv6
  • 域名
    使用字符串对域名进行唯一的标识
  • 域名服务器
    负责解析域名并转换为IP地址
  • 端口
    区分服务器上不同的服务
    一个服务器只能对应单个服务
    默认端口是80端口

http.createServer() 创建 http 服务器对象

Serve.prototype.on() 规定监听http请求的回调函数

Serve.prototype.listen() 启动 HTTP 服务器并监听http请求

实现基于url的响应
1 获取url地址
2 设置默认返回内容
3 处理数据并返回

express 库

基于 node 的 web 开发框架

快速创建 API 接口服务器与 Web 网站服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 导入
const express = require('express');

// 创建服务器
const app = express();

// 启动服务器
app.listen(8000, () => {
console.log('express server running at http://127.0.0.1:8000');
});

// 监听请求
// req 请求对象
// res 响应对象
app.get('/:id/user', (req, res) => {

// 获取查询参数 `req.query`

// 获取动态参数{如 /:id/} `req.params`

// 发送请求内容 `res.send()`
res.send('get!!!');

});

// 托管静态资源|注册全局中间件
// 外部 http://localhost:8000/0.css
// 内部 /public/0.css
// 托管多个静态资源目录,只需多次调用 express.static() 方法
app.use(express.static('public'));
// 挂载路径前缀
// 外部 http://localhost:8000/static/0.css
// 内部 /public/0.css
app.use('/static/', express.static('public'));

nodemon

监听本地项目文件变动并自动重启项目(类似前端 live server 的作用)

直接使用 nodemon file 指令执行项目

express 路由

一种映射关系,express中指的是客户端的请求与服务器处理函数之间的映射关系
app.METHOD(PATH, HANDLER)

路由模块化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// router.js
const express = require('express');

const router = express.Router();

router.get('/', (req, res) => {});
router.post('/', (req, res) => {});

module.exports = router;

// main.js
...
const router = require('./router.js');
app.use(router);

express 中间件

请求过程中可以调用中间件对请求进行多次预处理

实质是一个 function

next 函数实现多个中间件连续调用,表示启用下一个中间件

1
2
3
4
5
6
7
8
9
// 全局注册中间件
app.use((req, res, next) => {
console.log('mid');
next();
});
// 同时注册多个中间件只需多次调用app.use即可

// 局部注册中间件
app.post('/', (req, res, next) => {}, (req, res) => {});

需在路由之前注册中间件
可以对请求调用多个中间件进行处理
注意执行完中间件代码,需调用next方法
调用next方法后不应执行其他的任何的代码
连续多个中间件之间共享req与res对象

CORS

使用 cors 包

1
2
3
const cors = require('cors');

app.use(cors());

只需服务器做配置,客户端无需做额外的配置

响应头部带 Access-Control-Allow-Origin 字段,表示允许来源的域的名称
Access-Control-Allow-Headers 声明允许的请求头字段,Accept Accept-Language Content-Language DPR Downlink Save-Data Viewport-Width Width Content-Type
Access-Control-Allow-Methods 声明允许的请求方法,默认GET POST HEAD可,其他均需声明

  • 简单请求
    请求方式与请求头部字段有限

  • 预检请求(预先发送OPTION请求确定是否可请求,仅成功后才会发送实际请求)
    其他

mysql.js

在 node 中访问 MySQL 数据库的 js 库

Web 开发模式

  1. 基于服务端渲染的传统 Web 开发模式
    页面由服务器动态生成
    前端耗时少
    利于SEO
    占用服务器端资源
    不利于前后端分离开发效率低
  2. 基于前后端分离的新型 Web 开发模式
    依赖于 Ajax 技术,即前端使用接口,后端提供接口
    开发体验好
    用户体验好
    减轻服务器端渲染压力
    不利于SEO

身份认证

出于安全性考虑,需要对用户身份进行认证

(服务器渲染)Session 认证机制
(前后端分离)JWT 认证机制

Session 认证机制

  • HTTP 协议的无状态性

HTTP 请求独立,服务器无法主动保留每次 HTTP 请求的状态

  • 突破无状态性

使用 Cookie

  • Cookie

一段存储在用户浏览器中的字符串
可以存储一些特有信息
由名称、值及一些可选属性(有效期、安全性、使用范围等)构成
不同域名下Cookie相互独立
每次客户端请求均会自动发送当前域名下所有未过期的Cookie

1
2
3
4
<!-- 设置cookie -->
Set-Cookie: token=1dw21qde43s;
<!-- 发送cookie -->
Cookie: token=1dw21qde43s;

客户端登录,服务器生成对应的cookie发回客户端保存;之后客户端每次请求均将带cookie,服务器需验证通过后再进行操作返回响应内容

es6

es6

ES6 标准入门

2022.03.22
No.1

let 与 const

  • 具有块状作用域,仅在声明的代码块内可使用

  • 不存在变量提升现象

  • 仅可在变量声明后使用,声明之前不可使用,即暂时性死区(TDZ)现象

  • 不允许重复声明

  • const 声明常量,且需立即初始化

  • 原理可以认为是在声明仍会提到块顶部创建变量区域,但会阻止在声明位置后的使用

  • for 循环的条件部分可视为父作用域,循环体部分可视为子作用域

块作用域

  • 内层作用域可以覆盖外层作用域的变量
  • 外层作用域无法使用内层作用域的变量
  • 函数声明在块作用域的行为类似于 var(浏览器)

顶层对象

globalThis

  • 浏览器:window

  • Node:global

  • var 命令与 function 命令声明全局变量是顶层对象属性

  • let 命令、const 命令与 class 命令声明的不是顶层对象属性

解构赋值

  • 数组

let [a, [b], c = true, ...d] = [1, [2], 3, 4, 5, 6]4
a = 1 b = 2 c = 3 d = [4, 5, 6]

根据数组的位置提取值,匹配不到返回 undefined
允许默认值,仅 undefined 会起效
相当于模式匹配

应为可遍历结构(包含数组、Set 实例)

  • 对象

变量应与对象属性同名
取值没有次序

let { log: loge, sin, cos } = Math;

允许重命名变量

2022.03.23
No.2

Promise

Promise 含义

promise 语法上来说是一个对象,它保存了一个未来才会结束的事件的结果,可以用于获取异步操作的结果,是用于异步编程的一种常用的强大的工具,可以解决“回调地狱”问题

promise 对象具有三种状态:pending进行中、fulfilled已成功、rejected已失败,它的状态仅由异步执行的结果决定

promise 对象状态改变只能为 pending->fulfilledpending->rejected,且状态改变一旦发生,就无法改变,会一直保持这个结果

promise 对象创建后即无法取消,pending 状态时无法得知事件进展,无法在未设置回调函数时捕获错误

new Promise()

1
2
3
4
5
6
7
const promise = new Promise(function(resolve, reject) {
if(/*success*/) {
resolve(result);
} else {
reject(error);
}
});

promise 对象一旦新建就会立即执行
promise 对象接受一个函数作为参数,该函数参数分别为 resolve 和 reject,它们都可以根据需要接收参数,并包装成 Promise 对象返回(若已是 Promise 对象则直接返回)
resolve 函数将 promise 对象状态从 pending 改变为 fulfilled
reject 函数将 promise 对象状态从 pending 改变为 rejected

Promise.prototype.then()

1
2
3
4
5
6
7
8
promise.then(
function (result) {
// do something when success
},
function (error) {
// do something when fail
}
);

then 方法指定 promise 对象的处理回调函数,接收两个方法作为参数,第一个方法处理 fulfilled 状态的回调函数,第二个方法处理 rejected 状态的回调函数,两个方法都是可选的
then 方法返回一个新的 Promise 实例,因此 Promise 可以具有链式写法,链式的 then 方法会依次调用

Promise.prototype.catch()

相当于 .then(null | undefined, rejection) 指定 Promise 返回错误时的回调函数,包括异步操作抛出错误引起状态改变为 rejected 和回调函数运行时抛出的错误

1
2
3
4
promise.catch((error) => {
// do something to deal with the error
console.log(error);
});

一般建议不在 then 方法内定义错误的处理方法,而是统一在最后的 catch 方法统一处理
(也比较符合 try-catch 语句的写法)

处理完成后返回的 Promise 实例的状态会重置为 fulfilled

Promise.prototype.finally()

finally 方法绑定无论 fulfilled 状态还是 rejected 状态都会执行的方法

ES2018 引入

1
2
3
promise.finally(() => {
// do something to deal with the error
});

该方法无法接收参数
实质为 then 方法的特例

2022.03.26
No.3

Promise.resolve()

返回一个 Promise 实例

  • 参数是 Promise 实例 :直接返回,不做修改
  • 参数具有 then() 方法 :转为 Promise 实例并立即调用 then() 方法
  • 参数不具有 then() 方法 :返回一个 fulfilled 状态的 Promise 实例
  • 无参 :返回一个 fulfilled 状态的 Promise 实例

Promise.reject()

返回一个 rejected 状态下的 Promise 实例

Promise.all()

const promiseAll = Promise.all([promise1, promise2]);

该方法将多个 Promise 实例合并为一个新的 Promise 实例
以数组形式接收需包装的 Promise 实例,若接收到非 Promise 实例参数会自动转为 Promise 实例

  • 若所有 Promise 实例状态均变成 fulfilled,包装后的新 Promise 实例状态才会变成 fulfilled
  • 反之有任一一个 Promise 实例状态变成 rejected,包装后的新 Promise 实例状态即会变成 rejected

需要注意的是,Promise 实例的 catch 方法会阻碍装后的新 Promise 实例 catch 方法的错误捕获

1
2
3
4
5
Promise.all([p1, p2])
.then(([pp1, pp2]) => {
// do something with pp1 & pp2
})
.catch(console.error);

Promise.race()

语法及参数返回值格式同 all

  • 若有一个 Promise 实例状态均变成 fulfilled,包装后的新 Promise 实例状态就会变成 fulfilled
  • 反之若所有的 Promise 实例状态变成 rejected,包装后的新 Promise 实例状态才会变成 rejected

Promise.allSettled()

语法及参数返回值格式同 all

  • 类似 all 方法
  • 仅在所有 Promise 实例状态变更后才发生状态变更

ES2020 引入

1
2
3
4
5
6
7
Promise.allSettled([p1, p2]).then((res) => {
// res:
// [
// { status: 'fulfilled', value: 42 },
// { status: 'rejected', reason: -1 }
// ]
});

res 是对象数组,均具有 status 属性代表 Promise 实例的状态;fulfilled 状态具有 value 属性,rejected 状态具有 reason 属性,分别代表 Promise 实例操作的返回值

Promise.any()

语法及参数返回值格式同 all

  • 类似 race 与 allSettled 方法
  • 仅在所有 Promise 实例状态变更后才发生状态变更

ES2021 引入

error 是 AggregateError 实例数组,代表各 Promise 实例的错误信息

2022.03.27
No.4

Generator 函数

Generator

  • Generator 函数是一个状态机,封装了多个内部状态
  • 执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数还是一个遍历器对象生成函数
  • 返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态(通过 yield 定义)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function* helloWorldGenerator() {
yield "hello";
yield "world";
return "ending";
}
let hw = helloWorldGenerator();

hw.next();
// { value: 'hello', done: false }
hw.next();
// { value: 'world', done: false }
hw.next();
// { value: 'ending', done: true }
hw.next();
// { value: undefined, done: true }
  • 调用 Generator 函数时会返回一个遍历器 Iterator 对象实例
  • 每次调用返回的 Iterator 对象实例的 next() 方法时从函数头部或上次停止位置开始执行,直至遇到下一个 yield 表达式或 return 语句为止
  • 每次调用 next() 方法返回的是一个对象,具有 done 属性,表示 Iterator 是否执行完毕;具有 value 属性,代表 yield 后的表达式或 return 后的表达式值(惰性求值)

yield

  • 若 Generator 函数不使用 yield,相当于单纯的暂缓执行函数
  • 关键字 yield 只能使用在 Generator 函数内
  • 若 yield 在表达式内使用需加小括号
    console.log('y' + (yield 'eah'))

next()

  • next() 方法可以带一个参数,会给出上一个 yield 表达式的返回值(因此第一次 next() 方法参数无效,可以理解是因为第一次调用 next() 方法会启动遍历器)

for-of

  • 可以使用 for-of 循环遍历 Generator 函数运行时生成的 Iterator 对象,且无需调用 next() 方法
  • 特别的, for-of 循环不会返回 return 语句的表达式值
  • 可以应用于遍历任意对象
1
2
3
4
for (let v of hw()) {
console.log(v);
}
// 'hello' 'world' 'ending'

throw

Generator 函数运行时生成的 Iterator 对象可以调用 throw 方法,在函数体外抛出错误并可被函数体内的 try-catch 块捕获
hw().throw();

return

Generator 函数运行时生成的 Iterator 对象可以调用 return 方法结束 Generator 函数执行,返回值是 return 的参数
hw().return();

next & throw & return

  • next 方法将 yield 表达式替换成一个值

  • throw 方法将 yield 表达式替换成一个 throw 语句

  • return 方法将 yield 表达式替换成一个 return 语句

    2022.03.28
    No.5

yield*

用于在 Generator 函数内执行另一个 Generator 函数

1
2
3
4
5
6
7
8
9
10
function* bar() {
yield "x";
yield* foo();
/**
* for (let v of foo()) {
* yield v;
* }
*/
yield "y";
}

语法上认为 yield* 表达式用于声明返回的是一个遍历器对象且是希望被遍历的,实际效果相当于一个 for-of 循环

可以利用 yield* 取出嵌套数组的所有成员

1
2
3
4
5
6
7
8
9
function* iterTree(tree) {
if (Array.isArray(tree)) {
for (let i = 0; i < tree.length; i++) {
yield* iterTree(tree[i]);
}
} else {
yield tree;
}
}

Generator 函数的 函数对象属性

可简写为

1
2
3
4
5
let obj = {
*myGeneratorMethod() {
// do something
},
};

Generator 函数的 this

Generator 函数 g 返回的遍历器 obj,是 g 的实例,而且继承了 g.prototype

  • Generator 函数无法被用作构造函数,即在 Generator 函数内部利用 this 添加属性无法起效
  • Generator 函数无法被 new 使用

状态机&协程&上下文

可以使用 Generator 函数实现状态机

1
2
3
4
5
6
7
8
var clock = function* () {
while (true) {
console.log("Tick!");
yield;
console.log("Tock!");
yield;
}
};

Generator 函数是一个半协程的函数,即只有 Generator 函数的调用者,才能将程序的执行权还给 Generator 函数

Generator 函数的上下文在暂停时会暂时退出堆栈但会冻结在当前状态,启动执行时会再次加入调用栈回复执行

Generator 与异步

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 封装异步常规方法
var fetch = require("node-fetch");
function* gen() {
var url = "https://api.github.com/users/github";
var result = yield fetch(url);
console.log(result.bio);
}
var g = gen();
var result = g.next();
// 介于 fetch 模块返回 promise 对象实例
result.value
.then(function (data) {
return data.json();
})
.then(function (data) {
g.next(data);
});

2022.03.29
No.6

async await

async let a function return a promise, await let a expression wait for a promise

async 函数是 Generator 函数的语法糖

  • 内置执行器,无需像 Generator 函数一样调用 next 方法
  • 语义清晰化,async 表明函数内含异步操作,await 表明其后的表达式需等待结果
  • 适用性更广,允许 Promise 对象和原始状态的值
  • async 函数返回 Promise 对象

async 函数内部遇到 await 会先返回一个 Promise 对象,当 await 后的异步操作完成时,才会继续执行函数体后面的语句

await 命令遇到非 promise 对象会直接返回对应的值
await 命令后的 promise 对象变为 rejected 状态,所在的整个 async 函数都会终止执行

建议将 await 命令放在 try-catch 代码块中

1
2
3
4
5
6
7
async function myFunction() {
try {
await somethingThatReturnsAPromise();
} catch (err) {
console.log(err);
}
}

可以让多个并发的异步任务使用 Promise.all 进行包装

1
let [foo, bar] = await Promise.all([getFoo(), getBar()]);

await 命令只能在 async 函数内使用

async 函数可以保留运行堆栈,错误信息不会被遗漏

Iterator

简介

Iterator 为各种不同的数据结构(部署了 Iterator 接口)提供了统一的访问接口

Iterator 遍历时,首先创建一个指向当前数据结构起始位置的指针对象,随后调用指针对象的 next 方法,依次访问数据结构的各个成员,直至指向数据结构的结束位置

每次遍历返回一个对象,包含 value 属性和 done 属性(同 Generator 函数)

Iterator 接口部署在 Symbol.iterator 属性上,其亦是判断是否可遍历的标准

原生 Iterator 接口数据结构有 Array、Map、Set、String、函数的 arguments 对象、NodeList 对象

1
2
3
4
5
// 使用数组的 iterator
let iter = [1, 2][Symbol.iterator]();
iter.next(); // { value: 1, done: false }
iter.next(); // { value: 2, done: false }
iter.next(); // { value: undefined, done: true }

调用

  • 解构赋值(数组、Set)
  • 扩展运算符 …
  • yield*
  • 数组遍历 for…of、Array.from()、Map()、Set()、WeakMap()、WeakSet()、Promise.all()、Promise.race()

实现

1
2
3
4
5
6
7
8
9
// 使用 Generator 函数
let myIterable = {
[Symbol.iterator]: function* () {
yield 1;
yield 2;
yield 3;
},
};
[...myIterable]; // [1, 2, 3]

return 与 throw 方法

  • return 遍历提前结束时调用,如 break 或 Error 发生
  • throw 配合 Generator 函数使用

for - of

可以遍历任意具有 Symbol.iterator 的对象或对象实例

1
2
3
for (let v of ["red", "green", "blue"]) {
console.log(v); // red green blue
}
  • for-in 循环获取对象的键名
  • for-of 循环获取对象的键值

遍历的对象方法

  • Object.entries() 返回一个遍历器对象,用来遍历[键名, 键值]组成的数组

  • Object.keys() 返回一个遍历器对象,用来遍历所有的键名

  • Object.values() 返回一个遍历器对象,用来遍历所有的键值

    2022.03.30
    No.7

字符串扩展

字符串 Unicode 表示更新

1
2
3
4
"\u{20BB7}";
// "𠮷"
"\u{41}\u{42}\u{43}";
// "ABC"

字符串遍历器接口

可以识别大于 0xFFFF 的码点而不是分开识别

1
2
3
for (let c of "foo") {
console.log(c);
}

模板字符串

使用反引号标识字符串

  • 可以定义多行字符串
  • 可以在字符串内嵌入变量乃至表达式及函数
  • 会保留多行字符串内部的空格和缩进
  • 内部使用反引号需转义
1
`${x} + ${y} = ${x + y}`;

标签模板

相当于向函数传入一个特殊的模板字符串数组,其具有 raw 属性,代表转义后的原字符串

1
2
3
4
5
6
7
8
9
// 两者等价
alert`hello`;
alert(["hello"]);

let a = 5,
b = 10;
tag`Hello ${a + b} world ${a * b}`;
// 等同于
tag(["Hello ", " world ", ""], 15, 50);

可以用于过滤 HTML 字符串,防止用户输入恶意内容(过滤 < > & 等特殊字符)
可用于多语言转换

字符串新增方法

  • includes(SearchString, [StartIndex]) 表示是否找到参数字符串
  • startsWith(SearchString, [StartIndex]) 表示参数字符串是否在原字符串头部
  • endsWith(SearchString, [StartIndex]) 表示参数字符串是否在原字符串尾部

方法均返回布尔值
方法均支持第二个参数,代表开始搜索的位置

  • repeat(RepeatCount) 将给定字符串重复指定的次数

参数应为有限的正整数
小数会取整
0 会返回空串
负数及 Infinity 会报错
NaN 等价于 0

  • padStart() 用于头部补全
  • padEnd() 用于尾部补全

ES2017 引入

第一个参数指定补全后字符串的长度
第二个参数指定用于补全的字符串,默认为一个空格

原字符串长度超出指定的长度,不起效
补全用字符串与原字符串长度之和超出最大长度会截取补全用的字符串

常用于为数值补全指定位数,或用于提示字符串格式

  • trimStart() 消除字符串头部空格,浏览器中同 trimLeft()

  • trimEnd() 消除字符串尾部空格,浏览器中同 trimRight()

  • matchAll() 返回正则表达式在当前字符串的所有匹配

  • replaceAll(searchValue, replacement) 替换字符串中所有的匹配到的字符串

searchValue 可以为字符串或带g修饰符的正则表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// $& 表示匹配的字符串,即`b`本身
// 所以返回结果与原字符串一致
"abbc".replaceAll("b", "$&");
// 'abbc'

// $` 表示匹配结果之前的字符串
// 对于第一个`b`,$` 指代`a`
// 对于第二个`b`,$` 指代`ab`
"abbc".replaceAll("b", "$`");
// 'aaabc'

// $' 表示匹配结果之后的字符串
// 对于第一个`b`,$' 指代`bc`
// 对于第二个`b`,$' 指代`c`
"abbc".replaceAll("b", `$'`);
// 'abccc'

// $1 表示正则表达式的第一个组匹配,指代`ab`
// $2 表示正则表达式的第二个组匹配,指代`bc`
"abbc".replaceAll(/(ab)(bc)/g, "$2$1");
// 'bcab'

// $$ 指代 $
"abc".replaceAll("b", "$$");

// replacement可以是一个函数
"aabbcc".replaceAll("b", () => "_");
// 'aa__cc'
  • at() 选取字符串指定位置的字符,允许负索引

    2022.03.31
    No.8

数值表示方法

  • 二进制 0b11
  • 八进制 0o11

转为十进制可使用 Number() 方法

数值分隔符

特点

  • 允许数值使用 _ 作为分隔符
  • 分隔符之间没有指定间隔的位数 12_34_56 12_345_567
  • 允许应用于小数与指数 0.123_21 1e1_234
  • 允许应用于其他进制的数值

注意点

  • 数值分隔符无法放在数值最前面或最后面
  • 数值分隔符不能连在一起使用
  • 小数的小数点前后不能有分隔符
  • 指数的 e 符号前后不能有分隔符
  • 进制前缀后不能加分隔符
  • 字符串转数值函数不支持数值分隔符 Number('123_456') // NaN parseInt('123_456') // 123

Number 对象新增方法

  • Number.isFinite()
    检测数值是否为有限的

    • 数值为 ±Infinity 或 NaN 返回 false,其他返回 true
    • 非数值一律返回 false
  • Number.isNaN()
    检测数值是否为 NaN

    • 仅 NaN 返回 true,其他均为 false

    与传统的全局方法 isFinite()和 isNaN()的区别,对于非数值类型,全局方法会调用 Number()方法转换再比较,而 Number 对象方法一律直接返回 false

  • Number.parseInt()

  • Number.parseFloat()
    将数值转换为整数与浮点数
    使用与相应的全局方法相同

  • Number.isInteger()
    判断数值是否为整数
    若数值的小数部分过小,可能会发生误判
    非数值一律返回 false

  • Number.EPSILON
    代表 js 所能够表示的最小精度数,实质是可接受的最小误差范围
    两个浮点数的差小于该数时,可以认为两浮点数相等

  • Number.MAX_SAFE_INTEGER 2^53-1

  • Number.MIN_SAFE_INTEGER -(2^53-1)
    表示 js 能够精确表示的整数的范围

  • Number.isSafeInteger()
    检测数值是否为能够精确表示的
    非数值或非整数一律返回 false

    2022.04.01
    No.9

Math 对象新增方法

大多数非数值参数会先调用 Number() 方法尝试转换

  • Math.trunc()
    对浮点数执行取整操作,去除小数部分
    空值或无法转为整数的值返回 NaN
  • Math.sign()
    判断数值的符号
    • 正数返回 +1
    • 负数返回 -1
    • 0 返回 0
    • -0 返回-0
    • 其他返回 NaN
  • Math.cbrt()
    计算数值的立方根
  • Math.clz32()
    “count leading zero bits in 32-bit binary representation of a number”
    将参数转为 32 位无符号整数形式,并返回 32 位数的前导 0 的个数
    小数只会考虑整数部分
    Math.clz32(0) // 32
    Math.clz32(1) // 31
    Math.clz32(1000) // 22
    Math.clz32(0b01000000000000000000000000000000) // 1
    Math.clz32
    Math.clz32(3.2) // 30
  • Math.imul()
    返回两数以 32 位有符号整数相乘的结果
    正常情况 Math.imul(a, b)与 a _ b 效果相同
    (0x7fffffff _ 0x7fffffff)|0 // 0 Math.imul(0x7fffffff, 0x7fffffff) // 1
    主要应用于获取大数相乘时的正确的低位数值
  • Math.fround()
    返回数的 32 位单精度浮点数形式
    绝对值超出 2^24 的数字会丢失精度
    Math.fround(0) // 0
    Math.fround(2 ** 24 - 1) // 16777215
    Math.fround(2 ** 24) // 16777216
    Math.fround(2 ** 24 + 1) // 16777216
    主要应用于将 64 位双精度浮点数转为 32 位单精度浮点数
  • Math.hypot()
    返回所有参数的平方和的平方根
    对于非数值类型参数,会先转为数值,若任一参数无法转换,即会返回 NaN
    Math.hypot(3, 4); // 5
    Math.hypot(); // 0
    Math.hypot(NaN); // NaN
    Math.hypot(3, 4, 'foo'); // NaN
    Math.hypot(-3); // 3
  • Math.log2()
    返回以 2 为底的 x 的对数
  • Math.log10()
    返回以 10 为底的 x 的对数
  • Math.log1p()
    返回 ln(1 + x)
  • Math.expm1()
    返回 e^x - 1
  • Math.sinh(x)
    返回 x 的双曲正弦
  • Math.cosh(x)
    返回 x 的双曲余弦
  • Math.tanh(x)
    返回 x 的双曲正切
  • Math.asinh(x)
    返回 x 的反双曲正弦
  • Math.acosh(x)
    返回 x 的反双曲余弦
  • Math.atanh(x)
    返回 x 的反双曲正切

BigInt 类型

ES2020 引入

  • 只能用于表示整数

  • 可以表示任意位数的整数
    2172141653n * 15346349309n // 33334444555566667777n
    2172141653 * 15346349309 // 33334444555566670000

  • 允许使用各种进制表示整数
    0b1101n // 二进制
    0o777n // 八进制
    0xFFn // 十六进制

  • 通过后缀 n 声明整数
    1234 // 普通整数
    1234n // BigInt
    1n + 2n // 3n

  • typeof 运算符返回 ‘bigint’
    typeof 123n // 'bigint'

  • 可以使用-,不可以使用+
    -42n // CORRECT
    +42n // ERROR

  • 可以使用 BigInt()将其他类型的值转换为 BigInt 类型的变量

  • BigInt.asUintN(width, BigInt)
    给定的 BigInt 转为 0 到 2^width - 1 之间对应的值。

  • BigInt.asIntN(width, BigInt)
    给定的 BigInt 转为 -2^(width-1) 到 2^(width-1) - 1 之间对应的值。

  • BigInt.parseInt(string[, radix])
    近似于 Number.parseInt(),将一个字符串转换成指定进制的 BigInt

  • 大多数运算符,除>>>与+外,均可应用于 BigInt 对象

    2022.04.02
    No.10

数组扩展

Array 对象新增方法

  • Array.from()
    将类数组对象(具有 length
    属性)及可遍历对象(具有 Iterator 接口)转为数组
    允许接受第二个参数即回调函数,作用类似 map 方法,对元素进行处理并放入返回的数组

    • 转换各种值为数组
    • 将字符串转为数组以判断字符串正确的长度
    1
    2
    3
    4
    5
    6
    7
    8
    let arr2 = Array.from({
    0: "a",
    1: "b",
    2: "c",
    length: 3,
    }); // ['a', 'b', 'c']
    Array.from([1, 2, 3], (x) => x * x);
    // [1, 4, 9]
  • Array.of()
    将一组值转换为数组
    Array.of(3, 11, 8) // [3,11,8]

  • Array.prototype.copyWithin()
    将当前数组内部指定位置成员复制至其他位置并返回当前数组
    Array.prototype.copyWithin(target, start = 0, end = this.length)

    • target 开始替换数据位置
    • start 开始读取数据位置
    • end 结束读取数据位置
      [1, 2, 3, 4, 5].copyWithin(0, 3, 4)
  • Array.prototype.find()
    传入一个回调函数,返回第一个符合条件的值

  • Array.prototype.findIndex()
    传入一个回调函数,返回第一个符合条件的值的下标

  • Array.prototype.includes()
    查找数组内是否包含指定的值

  • Array.prototype.fill()
    使用给定值填充一个数组
    new Array(3).fill(7) // [7, 7, 7]
    ['a', 'b', 'c'].fill(7, 1, 2) // ['a', 7, 'c']

  • Array.prototype.entries()

  • Array.prototype.keys()

  • Array.prototype.values()
    keys()是对键名的遍历
    values()是对键值的遍历
    entries()是对键值对的遍历
    可以使用 for-of 循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
for (let index of ["a", "b"].keys()) {
console.log(index);
}
// 0
// 1

for (let elem of ["a", "b"].values()) {
console.log(elem);
}
// 'a'
// 'b'

for (let [index, elem] of ["a", "b"].entries()) {
console.log(index, elem);
}
// 0 "a"
// 1 "b"
  • Array.prototype.flat()
    展平多维数组形成低维的数组
    默认展平一层
    可以传入一个数值或 Infinity,代表期望展平的层数
    [1, [2, [3]]].flat(Infinity) // [1, 2, 3]

  • Array.prototype.flatMap()
    先对原数组各元素进行遍历后执行展平操作
    接受一个回调函数参数,只能展平一层

  • Array.prototype.at()
    根据数组下标获取元素
    允许负值

数组空位

不同方法对数组空位的处理方法不同

  • forEach(), filter(), reduce(), every() 和 some()都会跳过空位
  • map()会跳过空位,但会保留这个值
  • join()和 toString()会将空位视为 undefined,最终被处理成空字符串
  • Array.from()方法与扩展运算符会将数组的空位,转为 undefined
  • copyWithin()会连空位一起拷贝
  • fill()会将空位视为正常的数组位置
  • for…of 循环也会遍历空位
  • entries()、keys()、values()、find()和 findIndex()会将空位处理成 undefined

建议数组中不要出现空位


2022.04.05
No.11

运算符扩展

指数运算符 **

ES2016

右结合
2 ** 3 ** 2 // 相当于 2 ** (3 ** 2)

指数赋值运算符 **=

链判断运算符 ?.

ES2020

const firstName = (message && message.body && message.body.user && message.body.user.firstName) || 'default';
const firstName = message?.body?.user?.firstName || 'default';

在链式调用的时候判断左侧的对象是否为 null 或 undefined。如果是的,就不再往下运算,而是返回 undefined

  • obj?.prop // 对象属性是否存在
  • obj?.[expr] // 同上
  • func?.(…args) // 函数或对象方法是否存在

空值合并运算符 ??

ES2020

只有运算符左侧的值为 null 或 undefined 时,才会返回右侧的值

逻辑赋值运算符 &&= ||= ??=

可以用于为变量或属性设置默认值

opts.foo = opts.foo ?? 'bar';
opts.foo ??= 'bar';

对象 Object 新增方法

Object.is()

用来比较两个值是否严格相等
基本类似 === 运算符

区别:+0 不等于-0 ; NaN 等于本身

Object.assign()

用于对象合并,将源对象所有可枚举自身属性复制到目标对象

第一个参数是目标对象,剩余的参数是源对象

若只有第一个参数,会直接返回该对象
若该参数不是对象,会转为对象再处理
若该参数是 null 或 undefined 会报错
若非对象参数是剩余参数,会尝试转为对象,若失败则忽略跳过(实际只有字符串能以字符数组合入)
该方法只能拷贝源对象自身的可枚举属性,不能拷贝源对象继承属性,也不能拷贝不可枚举的属性

  • 浅拷贝
    源对象的对象属性拷贝的是引用

  • 替换同名属性
    对于同名属性,该方法会直接替换该属性而不是添加

  • 取值函数
    对于 get 函数,该方法会先求值再复制,不会复制 get 函数

  • 为对象添加属性

1
2
3
4
5
class Point {
constructor(x, y) {
Object.assign(this, {x, y});
},
}
  • 为对象添加方法
1
2
3
4
5
6
7
8
Object.assign(SomeClass.prototype, {
someMethod(arg1, arg2) {
···
},
anotherMethod() {
···
},
});
  • 克隆对象
1
2
3
function clone(origin) {
return Object.assign({}, origin);
}
  • 合并多个对象
1
2
const merge = (target, ...sources) => Object.assign(target, ...sources);
const merge = (...sources) => Object.assign({}, ...sources);
  • 指定属性默认值
1
2
3
4
5
6
7
8
const DEFAULTS = {
logLevel: 0,
outputFormat: "html",
};
function processContent(options) {
options = Object.assign({}, DEFAULTS, options);
// ...
}

2022.04.06
No.12

Object.getOwnPropertyDescriptors(Object)

ES2017 引入

返回指定对象的所有非继承的自身属性的描述对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Object.getOwnPropertyDescriptors({
foo: 123,
get bar() {
return "abc";
},
});
/**
* {
* foo: {
* value: 123,
* writable: true,
* enumerable: true,
* configurable: true,
* },
* bar: {
* get: [Function: get bar],
* set: undefined,
* enumerable: true,
* configurable: true,
* },
* }
*/
  • 可以用于配合 Object.defineProperties()方法方法正确拷贝对象(特别是对象的 get 和 set 属性)
  • 配合 Object.create()方法,将对象属性克隆到一个新对象(浅拷贝)
  • 实现对象之间的继承

__proto__ Object.setPrototypeOf() Object.getPrototypeOf()

__proto__ 用于读取并设置对象的原型对象
特别注意的是它仅规定在浏览器需要实现

Object.setPrototypeOf() Object.getPrototypeOf()
分别用于设置和获取对象的原型对象
不是对象的参数会自动转为对象

Object.keys() Object.values() Object.entries()

Object.keys() 返回包含对象自身所有的非继承的可遍历的属性键名的数组
Object.values() 返回包含对象自身所有的非继承的可遍历的属性键值的数组
Object.entries() 返回包含对象自身所有的非继承的可遍历的属性键值对数组的数组

1
2
3
4
var obj = { foo: "bar", baz: 42 };
Object.keys(obj); // ["foo", "baz"]
Object.values(obj); // ["bar", 42]
Object.entries(obj); // [ ["foo", "bar"], ["baz", 42] ]

Object.fromEntries()

相当于 Object.entries() 的逆操作
将一个键值对数组转为对象

1
2
3
4
Object.fromEntries([
["foo", "bar"],
["baz", 42],
]); // { foo: "bar", baz: 42 }

可以利用该方法与其逆方法实现map 数据结构对象之间的相互转换

对象扩展

属性的简洁表示方法

可以在大括号里面,直接写入变量和函数,作为对象的属性和方法,此时属性名就是变量名,属性值就是变量值

1
2
3
4
const foo = "bar";
const baz = {
foo,
};

方法的简洁表示方法

1
2
3
4
5
const o = {
method() {
return "Hello!";
},
};

get 与 set 的显示方法

1
2
3
4
5
6
7
8
9
10
11
12
const cart = {
_wheels: 4,
get wheels() {
return this._wheels;
},
set wheels(value) {
if (value < this._wheels) {
throw new Error("数值太小了!");
}
this._wheels = value;
},
};

属性名表达式

允许将变量值作为对象的属性名
注意:默认会将非对象变量值转为字符串

1
2
3
4
5
let propKey = "foo";
let obj = {
[propKey]: true,
["a" + "bc"]: 123,
};

2022.04.07
No.13

方法的 name 属性

  • 普通方法 方法名
  • 普通对象方法 方法名
  • get set 对象方法 get|set+方法名
  • Function 构造函数方法 anonymous
  • bind 方法 bound+方法名
  • Symbol 方法 Symbol 的描述

属性可枚举性与遍历

对象属性描述对象

对象的各属性均有一个相应的描述对象
可以使用 Object.getOwnPropertyDescriptor() 方法获取属性的描述对象

enumerable属性

属性 enumerable 用于描述对象属性是否可枚举

遍历方法

  • for…in 遍历对象自身的和继承可枚举非 Symbol 属性的属性
  • Object.keys(obj) 遍历对象自身可枚举非 Symbol 属性的属性
  • Object.getOwnPropertyNames(obj) 遍历对象自身非 Symbol 属性的属性
  • Object.getOwnPropertySymbols(obj) 遍历对象自身Symbol 属性的属性
  • Reflect.ownKeys(obj) 遍历对象自身的所有属性

遍历次序

  • 首先遍历所有数值键,按照数值升序排列
  • 其次遍历所有字符串键,按照加入时间升序排列
  • 最后遍历所有Symbol键,按照加入时间升序排列

super 关键字

指向当前对象的原型对象
(只能用于对象的方法内,只能在对象方法的简写法可使用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// correct
const obj = {
foo: "world",
find() {
return super.foo;
},
};

// error
const obj = {
foo: super.foo,
};
const obj = {
foo: () => super.foo,
};
const obj = {
foo: function () {
return super.foo;
},
};

super.foo 原理上等同于 Object.getPrototypeOf(this).foo (属性)或 Object.getPrototypeOf(this).foo.call(this) (方法)

对象扩展运算符

ES2018 引入

对象的解构赋值

1
2
3
4
5
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x; // 1
y; // 2
z; // { a: 3, b: 4 }
/* ...必须为最后一个参数 */

扩展运算符

取出对象的所有可遍历属性并拷贝到当前对象内,也可以应用于合并对象

1
2
3
4
5
6
7
let z = { a: 3, b: 4 };
let n = { ...z };
n; // { a: 3, b: 4 }

let ab = { ...a, ...b };
// 同名属性会依照出现的顺序被覆盖
// 可以设置对象属性的默认值以及修改现有对象的属性

实际效果等同于使用 Object.assign()方法

AggregateError 错误对象

ES2021 引入

AggregateError 在一个错误对象里面,封装了多个错误

AggregateError(errors[, message])
errors 以数组形式接收产生的错误对象(必须)
message 以字符串形式接收抛出时的提示信息(可选)
以上亦是对象实例的属性

1
2
3
4
5
6
7
8
9
const error = new AggregateError(
[
new Error("ERROR_11112"),
new TypeError("First name must be a string"),
new RangeError("Transaction value must be at least 1"),
new URIError("User profile link must be https"),
],
"Transaction cannot be processed"
);

2022.04.09
No.14

函数的扩展

函数默认值

1
2
3
4
5
6
7
8
// 形参
function f(a, b = 12) {
/* ... */
}
// 解构赋值
function g({ a, b = 1 }) {
/* ... */
}
  • 形参默认声明,因而无法再次声明
  • 不允许出现重名参数
  • 参数默认值是惰性求值,即每次重新计算值
  • 建议函数默认值放在末尾(不然为取到默认值,需要显式传参 undefined)
  • 指定默认值的函数,length 属性表示未指定默认值的参数个数(非末尾参数的默认值后的参数不再计入)【length 属性指的是函数预期传入的参数个数】
1
2
3
4
// 双重默认值
function fetch(url, { body = "", method = "GET", headers = {} } = {}) {
/* ... */
}

另外函数的形参部分运行时会生成一个独立的作用域

1
2
3
4
5
var x = 1;
function f(x, y = x) {
console.log(y);
}
f(2); // 2

可以利用默认值强制实现函数参数不可省略的特性

1
2
3
function foo(mustBeProvided = () => throw new Error("Missing parameter")) {
/* ... */
}

rest 参数

用于搭配一个数组变量,获取函数多余的参数
格式 ...变量名

函数的 length 属性,不包括 rest 参数

1
const sortNumbers = (...numbers) => numbers.sort();

另外,rest 参数必须为函数的最后一个参数

函数的严格模式

可以在函数内部设定严格模式

但是若函数参数使用了默认值解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式

  1. 可以设定全局的严格模式规避
  2. 可以将函数包裹在无参数的立即执行函数内部

函数的 name 属性

返回函数的函数名称

  • 匿名函数会返回实际的函数名
  • Function 构造函数创建的函数返回 ‘anonymous’
  • bind 返回的函数返回的有 bind 前缀

箭头函数

() => {}

尾调用优化

函数式编程
函数的返回调用另一个函数得到的结果(且应是函数的最后一步操作)

1
2
3
function f(x) {
return g(x);
}

它可以提高性能节省内存,尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用帧,因为调用位置、内部变量等信息都不会再用到了,只要直接用内层函数的调用帧,取代外层函数的调用帧就可以了

若尾调用自身,即尾递归
优点在于不易发生栈溢出错误

1
2
3
4
5
6
7
8
9
10
11
12
// 阶乘
function factorial(n, total) {
if (n === 1) return total;
return factorial(n - 1, n * total);
}
// Fibonacci 数列
function Fibonacci2(n, ac1 = 1, ac2 = 1) {
if (n <= 1) {
return ac2;
}
return Fibonacci2(n - 1, ac2, ac1 + ac2);
}

尾递归优化起效必须开启严格模式

函数参数尾逗号

ES2017 生效

允许函数最后一个参数出现逗号

Function.prototype.toString() 优化

ES2019 生效

会完全返回一模一样的原始代码(包括注释、空格等等)

catch 的参数忽略

允许 catch 语句忽略参数

1
2
3
4
5
try {
// ...
} catch {
// ...
}

2022.04.10
No.15

Map 与 Set

Set

Set 类似于数组,但是 Set 成员的值都是唯一的,没有重复的值

Set 构造方法

  • new Set()
  • new Set([1, 2, 3])
    构造方法可以接受一个数组或其他具有 Iterator 接口的数据结构参数

去除数组重复成员

[...new Set(array)] > > Array.from(new Set(array))
去除字符串重复成员
[...new Set(string)].join('')

Set 对象添加值时,不会发生类型转换,且使用 Same-value-zero equality 判断值是否重复(类似===),特别的是任意对象均不相同

可以使用 Array.from() 方法将 Set 结构转为数组
可以利用扩展运算符对 Set 实例转为数组执行一些操作

Set 原型属性

  • Set.prototype.constructor Set
    构造函数,即 Set 函数
  • Set.prototype.size
    返回 Set 实例的成员数量

Set 原型{操作}方法

  • Set.prototype.add(value)
    向 Set 实例添加一个值
    返回 Set 结构本身
    因此该方法可以链式调用
  • Set.prototype.delete(value)
    删除某个值
    返回一个布尔值,表示删除是否成功
  • Set.prototype.has(value)
    检测该值是否为 Set 实例的成员
    返回一个布尔值
  • Set.prototype.clear()
    清除所有成员
    没有返回值
1
2
3
4
5
6
7
s.add(1).add(2).add(2);
s.size; // 2
s.has(1); // true
s.has(2); // true
s.has(3); // false
s.delete(2);
s.has(2); // false

Set 原型{遍历}方法

  • Set.prototype.keys()
    返回键名的遍历器

  • Set.prototype.values()
    返回键值的遍历器

  • Set.prototype.entries()
    返回键值对的遍历器

  • Set.prototype.forEach()
    使用回调函数遍历每个成员,分别执行某种操作
    没有返回值
    接受第一个参数作为将执行的回调函数,第二个参数作为绑定的 this 对象

    特别的,Set 结构键名和键值是同一个值,因此 keys 方法和 values 方法的行为完全一致

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let set = new Set(["red", "green", "blue"]);
for (let item of set.keys()) {
console.log(item);
// red green blue
}
for (let item of set.values()) {
console.log(item);
// red green blue
}
for (let item of set.entries()) {
console.log(item);
// ["red", "red"] ["green", "green"] ["blue", "blue"]
}
new Set([1, 4, 9]).forEach((value, key) => console.log(key + " : " + value));
// 1 : 1 4 : 4 9 : 9

Map

Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现(因为 Object 对象的键名只允许为字符串)

Map 构造方法

构造方法类似 Set 的构造方法,可以接受任意具有 Iterator 接口且每个成员都是一个双元素的数组的数据结构作为参数
Map 亦不允许出现键值相同的元素
特别的,Map 判断键值相同是基于内存地址的,因此对于对象而言,相同内容的对象可能被 Map 认为是不同的键值

Map 原型属性及方法

  • size
    返回 Map 结构的成员总数
  • Map.prototype.set(key, value)
    设置键对应的值
    若键已存在会覆盖已有的值
    返回当前的 Map 结构
    因此可以采取链式写法
  • Map.prototype.get(key)
    读取键对应的值
    查找成功返回键对应的值,否则返回 undefined
  • Map.prototype.has(key)
    检测某个键是否存在于当前 Map 对象内
    返回一个布尔值
  • Map.prototype.delete(key)
    删除某个键
    返回一个布尔值,表示是否删除成功
  • Map.prototype.clear()
    清除所有成员
    方法没有返回值
1
2
3
4
5
6
7
8
const map = new Map();
map.set("foo", "val");
map.size; // 1
map.get("foo"); // 'val'
map.has("foo"); // true
map.delete("foo"); // true
map.delete("foo"); // false
map.clear();
  • Map.prototype.keys()
    返回键名的遍历器
  • Map.prototype.values()
    返回键值的遍历器
  • Map.prototype.entries()
    返回所有成员的遍历器
  • Map.prototype.forEach()
    遍历 Map 的所有成员

同样,Map 的遍历顺序即插入顺序

WeakSet 及 WeakMap

WeakSet 只接受对象作为成员
WeakMap 只接受对象作为键名(null 除外),键值则没有限制
WeakSet 中的对象与 WeakMap 的键名所指向的对象,不计入垃圾回收机制

因此 WeakSet 和 WeakMap 是不可遍历的,且不具有 size 属性,且无法执行清空操作
WeakSet 和 WeakMap 的其他方法基本相同

它们主要应用于解决使用 Set 和 Map 时可能出现的内存泄漏问题

2022.04.11
No.16

WeakRef

ES2021 引入

对象的弱引用

直接使用 new WeakRef(target) 创建基于对象 target 的新对象,该对象是对对象 target 的弱引用,垃圾回收机制不会计入这个引用
新对象的引用不会妨碍原始对象 target 被垃圾回收机制清除

实例 deref() 方法可以判断原始对象是否已被清除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 作为缓存
function makeWeakCached(f) {
const cache = new Map();
return (key) => {
const ref = cache.get(key);
if (ref) {
const cached = ref.deref();
if (cached !== undefined) return cached;
}
const fresh = f(key);
cache.set(key, new WeakRef(fresh));
return fresh;
};
}
const getImageCached = makeWeakCached(getImage);

FinalizationRegistry

指定目标对象被垃圾回收机制清除以后,所要执行的回调函数

1
2
3
4
5
6
7
8
// 新建注册表实例,接受一个回调函数参数作为当该对象被回收时的回调函数
const registry = new FinalizationRegistry((heldValue) => {
// ....
});
// 注册表实例的register()方法注册所要观察的目标对象并确定将传入回调函数的参数
registry.register(theObject, "some value", theObject);
// unregister()方法可以取消注册当前的对象
registry.unregister(theObject);

Symbol

概述

原始数据类型 Symbol,表示独一无二的值,是一种类似于字符串的数据类型
Symbol 值通过 Symbol() 函数生成
可以添加一个字符串参数表示对 Symbol 实例的描述(若为对象则会调用 toString() 方法转为字符串)

1
2
let s = Symbol(); // typeof s === "symbol"
let s1 = Symbol("foo"); // Symbol(foo)

任意两个 Symbol 变量使用 === 运算符比较都是不等的

Symbol 无法与其他类型的值进行运算,否则会报错;但可以显式转为字符串与布尔值(恒为 true)

Symbol.prototype.description

ES2019 引入

表示 Symbol 的描述(实际上就是传入 Symbol 的参数)

1
2
const sym = Symbol("foo");
sym.description; // "foo"

Symbol 作属性名

Symbol 值可以作为标识符,用于对象的属性名,从而保证不会出现同名的属性

1
2
3
let a = {
[mySymbol]: "bar",
};

注意:Symbol 值作为对象属性名时,不能用点运算符,只能使用中括号运算符

Symbol 类型可以用于定义一组常量,可以替代魔术字符串的使用

Symbol 的遍历

Symbol 成员属性不会被大多数循环所遍历
但可以使用 Object.getOwnPropertySymbols() 方法与 Reflect.ownKeys() 获取用作属性名的 Symbol 值
因此可以用于为对象定义一些非私有的、但又希望只用于内部的方法

2022.04.12
No.17

Symbol 的方法

Symbol.for()

接受一个字符串作为参数,然后搜索有没有以该参数作为名称的全局环境的 Symbol 值,若存在,就返回这个 Symbol 值;否则就新建一个以该字符串为名称的 Symbol 值,并将其全局注册

1
2
3
4
Symbol.for("foo") === Symbol.for("foo");
// true
Symbol("bar") === Symbol("bar");
// false

Symbol.keyFor()

返回一个已登记的 Symbol 类型值的 key,否则返回 undefined

Symbol 的内置值

Symbol.hasInstance

对象的 Symbol.hasInstance 属性,指向一个内部方法,该内部方法会在其他对象使用 instanceof 运算符,判断是否为该对象的实例时调用

1
2
3
4
5
6
7
8
9
10
11
12
13
class M {
[Symbol.hasInstance](foo) {
return foo instanceof Array;
},
};
[1, 2] instanceof new MyClass() // true
class N {
static [Symbol.hasInstance](obj) {
return Number(obj) > 0;
},
};
1 instanceof N // true
-1 instanceof N // true

Symbol.isConcatSpreadable

Symbol.isConcatSpreadable 属性是一个布尔值
表示该对象用于Array.prototype.concat()时,是否可以展开

  • 默认数组可以展开,值为 undefined(true 亦可)
  • 类数组对象默认不可展开,值为 false,(设为 true 可展开)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A1 extends Array {
constructor(args) {
super(args);
this[Symbol.isConcatSpreadable] = true;
},
};
class A2 extends Array {
constructor(args) {
super(args);
},
get [Symbol.isConcatSpreadable] () {
return false;
},
};
/* 注意:实例内与类内的区别 */

Symbol.species

Symbol.species 属性,指向一个构造函数,在创建衍生对象时调用

1
2
3
4
5
class MyArray extends Array {
static get [Symbol.species]() {
return Array;
}
}

可以指定衍生对象的类型(相当于指定原型对象)

Symbol.match

Symbol.match 属性,指向一个函数,在执行str.match(myObject)时,如果该属性存在,会调用该属性,返回该方法的返回值

Symbol.replace

Symbol.replace 属性,指向一个方法,当该对象被String.prototype.replace方法调用时,会返回该方法的返回值
Symbol.replace 方法会收到两个参数,第一个参数是 replace 方法正在作用的对象;第二个参数是替换后的值

对象的 Symbol.search 属性,指向一个方法,当该对象被String.prototype.search方法调用时,会返回该方法的返回值

Symbol.split

对象的 Symbol.search 属性,指向一个方法,当该对象被String.prototype.split方法调用时,会返回该方法的返回值

Symbol.iterator

对象的 Symbol.iterator 属性,指向该对象的默认遍历器方法
对象进行 for…of 循环时,会调用 Symbol.iterator 方法,返回该对象的默认遍历器

1
2
3
4
myIterable[Symbol.iterator] = function* () {};
class Collection {
*[Symbol.iterator]() {},
};

特别的,这个方法应当是一个 Generator 函数

Symbol.toPrimitive

对象的 Symbol.toPrimitive 属性,指向一个方法,该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let obj = {
[Symbol.toPrimitive](hint) {
switch (hint) {
case "number":
return 123;
case "string":
return "str";
case "default":
return "default";
default:
throw new Error();
}
},
};
2 * obj; // 246
3 + obj; // '3default'
obj == "default"; // true
String(obj); // 'str'

该方法可以接受一个字符串参数

  • Number:该场合需要转成数值
  • String:该场合需要转成字符串
  • Default:该场合可以转成数值,也可以转成字符串

Symbol.toStringTag

对象的 Symbol.toStringTag 属性,指向一个属性的 get 方法,在该对象上面调用Object.prototype.toString方法时,如果这个属性存在,它的返回值会出现在 toString 方法返回的字符串之中,表示对象的类型
可以用来定制[object Object][object Array]中 object 后面的那个字符串

部分特殊的对象已具有自带的 Symbol.toStringTag 属性

Symbol.unscopables

对象的 Symbol.unscopables 属性,指向一个对象,该对象指定了使用 with 关键字时,哪些属性会被 with 环境排除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyClass {
foo() {
return 1;
}
get [Symbol.unscopables]() {
return { foo: true };
}
}
var foo = function () {
return 2;
};

with (MyClass.prototype) {
foo(); // 2 (没有时为1)
}

2022.04.13
No.18

class 语法

class 简介

ES6 引入了 class 关键字用于定义类,作为对象的模板
可以认为是构造函数的另外一种写法,用法完全和构造函数一样

1
2
3
4
5
6
7
8
9
10
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return "(" + this.x + ", " + this.y + ")";
}
}
const point = new Point(1, 2);
  • 实际上类模板内的所有方法实质是定义在构造方法的 prototype 对象上
  • prototype 对象的 constructor()属性,直接指向’类’的本身
  • 特别的,类内部定义的所有方法,都是不可枚举
  • 特别的,类必须使用new指令调用,否则会报错
  • 类内部默认是严格模式
  • 类不存在变量提升现象
  • 类的 name 属性返回类名
  • 类成员方法的 this 默认指向类的实例(因此不建议单独使用成员方法,除非绑定了 this 的指向)

constructor 方法

类的默认方法(必须的),使用 new 命令时会被调用

默认返回实例对象,即 this

class 实例

实例的属性除非显式定义在其本身(即定义在 this 对象上),否则都是定义在原型上(即 class 上)

类的所有实例共享一个原型对象(浏览器可以使用proto属性访问,亦可使用 Object.getPrototypeOf()获取实例的原型对象)

另外,如果需要修改原型对象,需要非常非常谨慎

取值函数与存值函数

存值函数和取值函数直接设置在属性的 Descriptor 对象上,会拦截赋值和读取行为

1
2
3
4
5
6
7
8
9
10
11
class MyClass {
constructor() {
// ...
}
get prop() {
return "getter";
}
set prop(value) {
console.log("setter: " + value);
}
}

属性表达式与 class 表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
/* 属性表达式 */
let methodName = "getArea";
class A {
[methodName]() {}
}

/* class表达式 */
const B = class {};

/* 立即执行的class表达式 */
let c = new (class {
constructor() {}
})();

2022.04.14
No.19

静态方法

在 class 内定义的方法加 static 关键字,使该方法不被实例继承而是直接通过类调用
静态方法的 this 关键字指向类本身
继承时父类的静态方法可以被子类继承,亦可通过 super 关键字调用

1
2
3
4
5
6
class Foo {
static classMethod() {
return "hello";
}
}
Foo.classMethod(); // 'hello'

实例属性

实例属性可以定义在类的顶层

1
2
3
4
5
6
class Foo {
count = 0;
get value() {
return this.count;
}
}

静态属性

定义在 class 本身的属性,而不是定义在实例对象上的属性

1
2
class Foo {}
Foo.prop = 1;

static 修饰静态属性

私有方法及私有属性

  1. 通过命名时前加下划线_加以提示
  2. 将变量名命名为 Symbol 值,增大获取的难度
  3. 将私有方法放在类外

新 method,使用#前缀

1
2
3
4
class Foo {
#count = 0;
#cause() {}
}

同样可以使用 in 运算符判断私有属性的存在(但只能在类内部使用),常规的继承也可以使用

静态块

在类生成时运行一次,且仅运行一次
主要用于对静态属性进行初始化
(内部可以使用类名或 this 指代当前类)

1
2
3
4
5
6
class C {
static x = 1;
static {
this.x; // 等价于C.x
}
}

new.target 属性

在构造函数之中,返回 new 命令作用于的那个构造函数,若不是 new 调用的,会返回 undefined
可以用来确定构造函数的调用方式
子类继承父类时,new.target 会返回子类

1
2
3
4
5
6
7
function Person(name) {
if (new.target !== undefined) {
this.name = name;
} else {
throw new Error("必须使用 new 命令生成实例");
}
}

2022.04.15
No.20

class 继承

使用 extends 关键字声明继承

1
2
3
4
5
6
7
8
class Point {
constructor() {};
}
class ColorPoint extends Point {
constructor() {
super();
};
}
  • constructor

    必须在显式声明的 constructor()方法内部显式调用 super()方法,否则会报错(未指定 constructor()方法会默认添加且内部会调用 super()方法)

    原因是需要先调用父类的构造方法才可以生成 this 对象,从而子类才可在 this 上添加方法及属性
    可以认为,任意子类方法都有一个 constructor()方法

  • 属性及方法

    子类会继承父类所有属性方法,包括静态属性与静态方法(不包括私有属性与私有方法)
    但如果子类定义了私有属性的读写非私有方法,即可通过方法读写私有属性

super 关键字

  • super 作为函数调用时,代表父类的构造函数

    super 方法只能用于子类的构造函数内

  • super 作为对象使用时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类

    实例方法调用 super 内部 this 指向调用 super 的子类的实例
    静态方法调用 super 内部 this 指向 super 所在的子类

  • 由于对象总是继承其他对象,因此实际上任意对象中均可使用 super 关键字

prototype 属性和 __proto__ 属性

class 同时具有以上两种属性

子类

  • 子类 __proto__ 属性指向父类
  • 子类 prototype 属性的 __proto__ 属性,指向父类的 prototype 属性
1
2
3
4
5
class A {}
class B extends A {}

B.__proto__ === A; // true
B.prototype.__proto__ === A.prototype; // true
  • 作为一个对象,子类(B)的原型(proto属性)是父类(A)
  • 作为一个构造函数,子类(B)的原型对象(prototype 属性)是父类的原型对象(prototype 属性)的实例

子类实例

  • 子类实例的proto属性的proto属性,指向父类实例的proto属性
1
2
3
4
var a = new A(2, 3);
var b = new B(2, 3, "red");

b.__proto__.__proto__ === a.__proto__; // true
  • 子类的原型的原型,是父类的原型

    2022.04.16
    No.21

Module

模块

  1. CommonJS 服务器端
  2. AMD 浏览器端

ES6 模块通过 export 显式指定输出的代码,并使用 import 导入

这是编译时加载,可以实现静态分析,可以提高加载效率

模块自动采用严格模式

export命令

规定模块的对外接口

  • 可以直接输出变量、函数、对象等
1
2
3
4
5
6
7
// 输出变量
export const a = 100;
const b = 200;
export { b };

// 输出函数及类class
export function c() {}
  • 通常export输出变量名称即其原本名称,但可以使用as关键字重命名
1
2
const d = 300;
export { d as D };
  • export指令规定的对外接口,必须与模块内部变量建立一一对应的关系

  • export输出的接口,与其对应的值是动态绑定关系,可以实时获取模块内部的值

import命令

加载模块

  • import命令接受一对大括号,内部指定从其他模块导入的变量名(该变量名必须与对外接口名称相同)
1
import { a, b } from "module.js";
  • 可以使用as关键字对输入变量重命名
1
import { c as C } from "module.js";
  • import输入的接口是只读的,无法对其重新赋值(若其为对象,可改变其的内容)

  • import 后的 from 规定模块文件的位置,相对路径与绝对路径均可,单独的模块名需要相应的配置文件给出模块的位置

1
import jQuery from "jquery";
  • import命令具有提升效果,会把变量提升到模块头部首先执行(因为 import 命令是编译阶段执行的,在代码运行之前)

  • import命令无法使用表达式与变量,也无法在 if、for 等块状作用域内执行

  • import 语句会执行所加载的模块

1
2
// 执行一次lodash模块,但不会导入任何值
import "lodash";

模块整体加载

使用*as实现

1
2
import * as Z from "module.js";
Z.c();

export default指令

为模块指定默认输出,用户可以自行定义任意的名称

1
2
3
4
5
// export.js
function foo() {}
export default foo;
// import.js
import FOO from "export.js";

该命令只能使用一次,因为一个模块只能有一个默认输出

本质上,export default就是输出一个叫做default的变量或方法,并且系统允许为它取任意名字

2022.04.17
No.22

exportimport的复用

1
export { foo } from "module.js";

相当于导入了模块并作为对外接口发放出去(但实际上并没有导入当前模块,不能直接使用)

1
2
3
4
5
6
7
// 其他一些用法
export { foo as FOO } from 'module';
export * from 'module';
export * as BAR from 'module';
export { default } from 'module';
export { foo as default } from 'module';
export { default as foo } from 'module';

模块的继承

1
2
3
4
5
6
7
8
export * from "circle";
export var e = 2.71828182846;
export default function (x) {
return Math.exp(x);
}

import * as math from "circleplus";
import exp from "circleplus";

跨模块常量

将 const 常量作为对外接口导出

1
2
export const A = 1;
import { A } from "./constants";

动态导入

使用import(specifier)动态导入模块,接受一个参数代表模块的位置,返回一个 Promise 实例(它是一个异步加载方法)

1
2
3
4
5
6
7
import(`./section-modules/${someVariable}.js`)
.then((module) => {
module.doSomeThing();
})
.catch((err) => {
console.error(err);
});
  • 按需加载
    在需要时再加载模块
  • 条件加载
    在if代码块内根据需要加载不同的模块
  • 动态模板路径加载
    动态生成希望加载的模块路径

可以结合 async - await 使用

1
2
3
4
5
6
7
8
9
async function main() {
const myModule = await import('./myModule.js');
const { export1, export2 } = await import('./myModule.js');
const [ module1, module2, module3 ] = await Promise.all([
import('./module1.js'),
import('./module2.js'),
import('./module3.js'),
]);
}

2022.04.18
No.23

Proxy 代理器

Proxy

Proxy 用于修改某些操作的默认行为,相当于在目标对象前添加一层拦截,可以对外界的访问进行过滤与改写

使用如下的方法生成一个对象的拦截器
const proxy = new Proxy(target, handler);
其中target代表将拦截的目标对象
handler代表拦截行为,是一个对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/** define */
var obj = new Proxy({}, {
get: function (target, propKey, receiver) {
console.log(`getting ${propKey}!`);
return Reflect.get(target, propKey, receiver);
},
set: function (target, propKey, value, receiver) {
console.log(`setting ${propKey}!`);
return Reflect.set(target, propKey, value, receiver);
}
});

/** test */
obj.count = 1
// setting count!
++obj.count
// getting count!
// setting count!
// 2

要使得Proxy起效,需要直接对Proxy实例进行操作而不是对目标对象进行操作
显而易见Proxy实例可以做其他对象的原型对象
同一个拦截器对象可以一次性拦截多个操作
可以把拦截器设置到proxy属性上var object = { proxy: new Proxy(target, handler) };因而可以在object对象上调用

Proxy 实例方法

  • get(target, propKey, receiver)

    1. 简介
      拦截对象属性的读取
      标对象某属性不可写且不可配置,则对该属性的get方法会报错
    2. 参数
      • target 目标对象
      • propKey 属性名
      • receiver 操作行为所针对的proxy实例(可选)
    3. 目标
      • proxy.foo
      • proxy['foo']
    4. 作用
      • 实现链式调用
  • set(target, propKey, value, receiver)

    1. 简介
      拦截对象属性的设置
      应返回一个布尔值(严格模式下返回 false 或 undefined 均会报错)
      目标对象的不可写属性,则对该属性的set方法不起效
    2. 参数
      • target 目标对象
      • propKey 属性名
      • value 属性值
      • receiver 操作行为所针对的proxy实例(可选)
    3. 目标
      • proxy.foo = v
      • proxy['foo'] = v
    4. 作用
      • 阻止内部属性的点运算符与中括号运算符访问,实现私有属性的效果
  • has(target, propKey)

    1. 简介
      拦截propKey in proxy的操作
      目标对象不可配置或不可扩展时使用has方法会报错
      返回一个布尔值
      特别的其对 for - in 循环不起效
    2. 参数
      • target 目标对象
      • key 查询的属性名
    3. 目标
      • foo in proxy
    4. 作用
      • 阻止对内部属性的in运算符访问,实现私有属性的效果
  • deleteProperty(target, propKey)

    1. 简介
      拦截delete操作
      返回一个布尔值
      目标对象的不可扩展属性无法被删除,否则会报错
    2. 参数
      • target 目标对象
      • propKey 删除的属性名
    3. 目标
      • delete proxy[propKey]
    4. 作用
      • 阻止对内部属性的in运算符访问,实现私有属性的效果
  • ownKeys(target)

    1. 简介
      拦截读取对象自身属性操作
      返回一个数组(数组成员只能是字符串或Symbol值,其他值出现会报错)
      会自动过滤不存在的属性、不可遍历的属性,Symbol值属性
      不可配置的属性必须被返回,否则报错
      不可扩展的目标对象必须包含所有属性,否则会报错
    2. 参数
      • target 目标对象
    3. 目标
      • Object.getOwnPropertyNames(proxy)
      • Object.getOwnPropertySymbols(proxy)
      • Object.keys(proxy)
      • for...in循环
  • getOwnPropertyDescriptor(target, propKey)

    1. 简介
      拦截Object的获取属性描述对象方法
      返回属性的描述对象或undefined
    2. 参数
      • target 目标对象
      • propKey 希望获取属性描述对象的属性名
    3. 目标
      • Object.getOwnPropertyDescriptor(proxy, propKey)
  • defineProperty(target, propKey, propDesc)

    1. 简介
      拦截Object的定义属性方法
      返回一个布尔值
      不可扩展的目标对象无法被删除,否则会报错
      目标对象的不可写属性或者不可配置属性无法被改变
    2. 参数
      • target 目标对象
      • propKey 删除的属性名
      • propDesc 删除的属性描述对象
    3. 目标
      • Object.defineProperty(proxy, propKey, propDesc)
      • Object.defineProperties(proxy, propDescs)
  • preventExtensions(target)

    1. 简介
      拦截Object的标记对象不可扩展方法
      必须返回一个布尔值
      仅目标对象不可扩展时才能返回true,否则会报错(因此通常内部需要调用一次Object.preventExtensions(proxy)方法)
    2. 参数
      • target 目标对象
    3. 目标
      • Object.preventExtensions(proxy)
  • getPrototypeOf(target)

    1. 简介
      拦截获取原型对象操作
      返回一个对象或null
      不可扩展的目标对象,必须返回目标对象的原型对象
    2. 参数
      • target 目标对象
    3. 目标
      • Object.prototype.__proto__
      • Object.prototype.isPrototypeOf()
      • Object.getPrototypeOf()
      • Reflect.getPrototypeOf()
      • instanceof
  • isExtensible(target)

    1. 简介
      拦截判断对象可扩展性操作
      返回一个布尔值
      其返回值必须与目标对象的isExtensible属性一致
    2. 参数
      • target 目标对象
    3. 目标
      • Object.isExtensible(proxy)
  • setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截

    1. 简介
      拦截设置原型对象方法
      必须返回一个布尔值
      不可扩展的目标对象不得改变其原型对象
    2. 参数
      • target 目标对象
      • proto 将设置的原型对象
    3. 目标
      • Object.setPrototypeOf(proxy, proto)
  • apply(target, object, args)

    1. 简介
      拦截 Proxy 实例作为函数调用的操作
    2. 参数
      • target 目标对象
      • ctx 目标对象的上下文对象this
      • args 目标对象的参数数组
    3. 目标
      • proxy(...args)
      • proxy.call(object, ...args)
      • proxy.apply(...)
  • construct(target, args)

    1. 简介
      拦截 Proxy 实例作为构造函数调用的操作
      返回必须为一个对象
    2. 参数
      • target 目标对象(必须是函数)
      • args 构造函数的参数数组
      • newTarget new命令作用的构造函数
    3. 目标
      • new proxy(...args)
    4. 作用
      • 阻止对内部属性的in运算符访问,实现私有属性的效果

Proxy 静态方法

  • Proxy.revocable()
    返回一个可取消的 Proxy 实例
    可以应用于:若目标对象不允许直接访问,必须通过代理访问,一旦访问结束,就收回代理权,不允许再次访问

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    let target = {};
    let handler = {};

    let {proxy, revoke} = Proxy.revocable(target, handler);

    proxy.foo = 123;
    proxy.foo // 123

    revoke();
    proxy.foo // TypeError: Revoked

issue of this on Proxy

Proxy 代理情况下,目标对象内部的this会指向 Proxy 实例
此时需要使用bind、apply等方法绑定this的指向

2022.04.19
No.24

Reflect

Reflect 对象是 Object 对象的更新

svg

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<svg width="500" height="500" style="background-color: #eee;">

<!-- 矩形 rect -->
<rect width="100" height="100" x="100" y="100" rx="10" ry="10"></rect>
<!-- 圆形 circle -->
<circle cx="250" cy="250" r="100"></circle>
<!-- 椭圆 ellipse-->
<ellipse cx="475" cy="450" rx="25" ry="50"></ellipse>
<!-- 直线 line -->
<line x1="0" y1="0" x2="500" y2="500" stroke="green"></line>
<!-- 折线 polyline -->
<polyline points="500 0, 100 100, 0 500" stroke="blue" fill="none"></polyline>
<!-- 多边形 polygon -->
<polygon points="500 0, 400 400, 0 500" stroke="none" fill="green"></polygon>
<!-- 直线路径 path -->
<path d="M 0 0 L 50 50 L 50 100 L 100 400 L 400 400 L 400 100 L 50 50 Z" stroke="orange" fill="none" ></path><path d="M 0 0 l 250 150 l 100 0 l 0 -100 l 50 50 l 50 0 l 0 350 l -350 0 l 0 -50 l -50 -50 l 100 0 l 0 -100 Z" stroke="red" fill="none" stroke-width="5" stroke-dasharray="25 5 10 5" stroke-dashoffset="5" stroke-linecap="round" stroke-linejoin="round"></path>
<!--
属性样式 直接设置在元素属性上
内联样式 设置在元素 style 属性内
内部样式 写在 style 标签内
外部样式 写在独立的 css 文件中
-->
<!--
svg 常见属性
fill 填充颜色
stroke 描边颜色
fill-opacity 填充颜色的不透明度
stroke-opacity 描边颜色的不透明度
stroke-width 描边宽度
stroke-dasharray 描边样式 - 可以用于设置虚线
stroke-dashoffset 设置偏移量
stroke-linecap 线帽样式
butt 平头 | 默认
round 圆头
square 方头
stroke-linejoin 拐角样式
miter 尖角 | 默认
round 圆角
bevel 平角
shape-rendering 消除锯齿
crispEdges 关闭反锯齿功能
geometricPrecision 开启反锯齿功能
-->
<!--
svg 支持颜色
颜色关键字
十六进制
RGB 和 RGBA
HSL 和 HSLA
-->

<!-- 文本元素 text -->
<text x="250" y="250" fill="pink" font-size="50" font-weight="bold" text-decoration="underline" text-anchor="middle" dominant-baseline="middle">SVG</text>
<!-- 多行文本 tspan -->
<text font-size="25">
<tspan x="400" y="380">S</tspan>
<tspan x="400" y="400">V</tspan>
<tspan x="400" y="420">G</tspan>
</text>
<!--
文本元素属性
font-size 字号
font-weight 粗体
text-decoration 装饰线
text-anchor 水平对齐方式
dominant-baseline 垂直对齐方式
writing-mode 文字方向
-->

<!-- 超链接 a -->
<a xlink:href="https://developer.mozilla.org/zh-CN/docs/Web/SVG" xlink:title="svg" target="_blank">
<text x="50" y="50" font-size="25">SVG</text>
</a>

<!-- 图片 image -->
<image xlink:href="https://img.zcool.cn/community/0167b95fc9ea7a11013ee04dc55982.jpg@1280w_1l_2o_100sh.jpg" width="50" height="50" x="100" y="100"></image>

</svg>
webpack

webpack

前端工程化

  • 模块化
    • js模块化
    • css模块化
    • 资源模块化
  • 组件化
    • 复用UI结构、样式、行为
  • 规范化
    • 目录结构划分
    • 编码规范化
    • 接口规范化
    • 文档规范化
    • git分支管理
  • 自动化
    • 自动化构建
    • 自动部署
    • 自动化测试

标准化企业级项目开发过程:工具、技术、流程、经验

grunt gulp => webpack(主) parcel => vite

webpack

前端项目工程化

  • 代码压缩混淆
  • 处理JavaScript兼容性
  • 性能优化

安装webpack

npm i webpack webpack-cli -D

配置webpack

在webpack.config.js文件内
保存webpack的打包设定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 导入 path 包
const path = require('path');

module.exports = {
/**
* mode 标记构建模式
* development 开发模式 不会代码压缩或性能优化 打包速度快
* production 发布模式 会代码压缩与性能优化 打包速度慢
* none 无模式
*/
mode: 'development',
/**
* entry 输入文件路径,开始打包的文件路径
*
* __dirname:当前文件绝对路径
*/
entry: path.join(__dirname, './src/index.js'),
/**
* output 输出设定
*/
output: {
/**
* path 输出文件路径
*/
path: path.join(__dirname, './dist'),
/**
* filename 输出文件名称
*/
filename: 'main.js',
},
}

在package.json文件内

1
2
3
"scripts": {
"dev": "webpack"
}

使用webpack

npm run dev


webpack-dev-server

实时更新修改文件,从而能够随时观察编辑效果
实际搭建一个本地服务器,把实时改变的文件放在内存内,以加快访问速度

  1. 安装 npm i webpack-dev-server -D

  2. 修改 package.json 文件如下:

    1
    2
    3
    "scripts": {
    "dev": "webpack serve"
    }
  3. 可通过 npm run dev 编译

  4. 访问 https://localhost:8080

配置 webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
devServer: {
/**
* 初次打包完成后自动打开浏览器
*/
open: true,
/**
* 指定host名
*/
// host: '127.0.0.1',
/**
* 指定端口
*/
// port: 8080,
},
}

html-webpack-plugin

编译时实时移动 html 文件至项目根目录
自动注入项目打包后的 js 文件和其他文件

  1. 安装 npm i html-webpack-plugin -D
  2. 配置 webpack.config.js
1
2
3
4
5
6
7
8
9
10
11
12
// 导入 HtmlPlugin 包
const HtmlPlugin = require('html-webpack-plugin');

// 添加 plugins 设置
{
plugins: [
new HtmlPlugin({
template: './src/index.html',
filename: './index.html',
}),
],
}

loader

由于 webpack 仅可处理 js 及 json 文件
加载器:协助 webpack 处理特定的文件模块

  • css-loader 处理 css 文件
  • less-loader 处理 less 文件
  • babel-loader 处理高级 js 语法

CSS-loader

协助处理 css 文件

  1. 安装 npm i style-loader css-loader -D

  2. 配置 webpack.config.js 内的 module 选项

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    {
    // 第三方模块的匹配规则
    module: {
    // 规则数组
    rules: [
    {
    // 正则表达式匹配的文件类型
    test: /\.css$/,
    // 使用的 loader
    // 特别的: loader 中的顺序不可交换,会按从后往前的顺序调用
    use: [
    'style-loader',
    'css-loader',
    ],
    }
    ],
    },
    }
  3. 在 index.js 中导入 css 文件
    import './css/index.css';

less-loader

协助处理 less 文件

  1. 安装 npm i less less-loader -D

  2. 配置 webpack.config.js 内的 module 选项

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    {
    module: {
    rules: [
    {
    test: /\.less$/,
    use: [
    'style-loader',
    'css-loader',
    'less-loader',
    ],
    },
    ],
    },
    }
  3. 在 index.js 中导入 less 文件
    import './css/index.less';

url-loader&file-loader

协助处理图片
会把给定限制大小下的图片转为base64编码,否则仍使用url导入的方式

  1. 安装 npm i url-loader file-loader -D

  2. 配置 webpack.config.js 内的 module 选项

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    {
    module: {
    rules: [
    {
    test: /\.jpg|png|gif$/,
    // limit 指定转换图片的阈值
    use: 'url-loader?limit=8192',
    },
    ],
    },
    }
  3. 在 index.js 中导入图片
    import logo from './images/icon.png';

  4. 给img标签赋值
    $('#img').attr('src', logo);

babel-loader

  1. 安装 npm i babel-loader @babel/core @babel/plugin-proposal-decorators -D

  2. 配置 webpack.config.js 内的 module 选项

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    {
    module: {
    rules: [
    {
    test: /\.js$/,
    use: 'babel-loader',
    exclude: /node_modules/,
    },
    ],
    },
    }
  3. 配置 babel.config.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    module.exports = {
    plugins: [
    [
    '@babel/plugin-proposal-decorators',
    {
    legacy: true,
    },
    ],
    ],
    }

打包发布

package.json 配置

1
2
3
4
"scripts": {
// --mode production 指定发布时模式为 production
"build": "webpack --mode production"
}

优化js路径

1
2
3
4
output: {
path: path.join(__dirname, './dist'),
filename: 'js/main.js',
}

优化img路径

1
2
3
4
5
6
7
8
9
10
{
test: /\.jpg|png|gif$/,
use: {
loader: 'url-loader',
options: {
limit: 10240,
outputPath: 'images',
},
},
},

配置清理 dist 目录 clean-webpack-plugin

  1. 安装 npm i clean-webpack-plugin -D

  2. 导入与配置 webpack.config.js

    const {CleanWebpackPlugin} = require('clean-webpack-plugin');

    1
    2
    3
    4
    5
    6
    7
    plugins: [
    new HtmlPlugin({
    template: './src/index.html',
    filename: './index.html',
    }),
    new CleanWebpackPlugin(),
    ],

Source Map

信息文件,保存打包前代码的详细位置信息

webpack.config.js 添加 devTools: 'eval-source-map' 选项

建议发布时去除 source map 选项

只定位行号,不暴露源码:nosources-source-map 设定
定位行号且暴露源码:source-map 会生成一个独立文件

使用@导入文件

  • 配置
1
2
3
4
5
resolve: {
alias: {
'@': path.join(__dirname, './src/'),
},
},
  • 使用
    import msg from '@/msg.js';
react

react

React

React 概述

React 概念

React 用于构建用户界面的 JavaScript 库

MVC 中的 V {视图层}

React 特点

声明式
基于组件
应用范围广

react 基本使用

react 安装

npm i react react-dom

react 使用

1
2
<script type="text/javascript" src="./node_modules/react/umd/react.development.js"></script>
<script type="text/javascript" src="./node_modules/react-dom/umd/react-dom.development.js"></script>
1
2
const title = React.createElement('h1', null, 'Hello React');
ReactDOM.render(title, document.getElementById('root'));

React.createElement
返回 React 元素
第一个参数为元素名
第二个参数为元素属性
第三个及之后的参数为元素的子节点

ReactDOM.render
第一个参数为要渲染的 react 元素
第二个参数为将挂载的 DOM 对象

React 脚手架使用

npx create-react-app <my-app>

npx 在不安装脚手架包情况下使用脚手架包提供的命令

npm init react-app <my-app>
yarn create react-app <my-app>

导入 React

创建 React 元素

渲染 React 元素

JSX 概述

JSX 基本使用

比 createElement 简洁

在 JS 中书写 HTML 格式代码

1
2
3
const title = <h1>Hello JSX</h1>;
const root = document.getElementById(root);
ReactDOM.render(title, root);

JSX 注意点

React 元素属性名使用驼峰命名法

class 属性需替换为 className 属性
for 属性需替换为 htmlFor 属性

无子节点的元素可以以单标签形式写

建议使用小括号包裹 JSX

JSX 嵌入 JS 表达式

单大括号

1
2
3
const title = <h1>Hello JSX</h1>;
const root = document.getElementById(root);
ReactDOM.render(title, root);

允许使用任意的 JS 表达式
但使用对象可能会出现 bug
不能使用任意的 JS 语句

条件渲染

函数 - ifelse
函数 - 三元表达式
函数 - 逻辑与运算符

列表渲染

使用数组 map 方法实现

1
2
3
4
5
6
const array = [1, 2, 3, 4, 5]
const list = (
<ul>
{array.map(v => <li key={v}>{v}</li>)}
</ul>
)

样式处理

行内样式

<h1 style={{ color: red; }}></h1>

类名 className

React 组件介绍

使用 React 组件介绍
从而实现完整的页面功能

函数组件

使用函数创建组件

  • 函数名称必须以大写字母开头
  • 函数组件必须有返回值,表示组件内容 | 返回值为 null,为无内容

渲染组件,直接使用函数名为组件标签名

类组件

使用 class 类创建组件

  • 类名称必须以大写字母开头
  • 类组件需继承 React.component 父类,以使用父类提供的方法
  • 类组件需提供 render 方法,且应有返回值,表示组件将渲染的内容

独立文件

单独组件放在单个JS文件内

事件绑定

示例如 onClick={ () => {} }
采用驼峰命名法

事件对象

合成事件(包含原生事件)
兼容性好

组件分类

函数组件 - 无状态组件
类组件 - 有状态组件

状态 - 数据

组件状态是私有的

受控组件 - value 绑定 state 变量,监听 change 事件实时改变 state 变量

非受控组件 - |

组件高级

组件通讯

组件 props | 父组件=>子组件

可以传递各种数据,包括对象、函数乃至JSX等
props 只读

  • 父->子 props属性传数据
  • 子->父 props属性传回调方法
  • 兄弟<->兄弟 状态共享至公共父组件,由公共父组件负责管理

跨多个组件的通讯 context
Provider 传送数据
Customer 接纳数据

props.children 组件标签的子节点

props 校验

使用 prop-types

设置propTypes
支持 array bool func number object string bigint symbol
element node elementType
instanceOf
oneOf oneOfType
arrayOf objectOf
required
shape
设置defaultProps

组件生命周期

仅类组件有生命周期

  • 创建时
    • constructor 初始化state 绑定this
    • render 渲染UI
    • componentDidMount 发送网络请求 DOM操作
  • 更新时
    • render
    • componentDidUpdate
  • 卸载时
    • componentWillUnmount

组件复用

  • render props 模式

    将单独的state及state方法封装为单独的组件
    利用 prop 传递参数
    传递函数以函数返回值作为将渲染的 UI 内容(或使用 children)

  • 高阶组件 HOC

    函数
    接受需包装的组件,返回增强的组件
    (名称约定以 with 开头)
    组件配置 displayName 作为组件名称

路由

SPA 单页面应用,单HTML页面的web应用程序

路由 - 配对路径何组件

  1. 安装 react-router-dom
  2. 导入组件 import { BrowserRouter as Router, Route, Link } from 'react-router-dom'
  3. Router 组件包裹整个应用
  4. Link 作为路由入口
  5. Route 配置路由规则和需要展示的组件|路由出口

Router 组件包裹整个应用,仅使用一次
包括 BrowserRouter 和 HashRouter

Link 组件作为导航链接
Route 组件指定路由展示组件相关信息

编程式导航
this.props.history.push
this.props.history.go

默认路由
path为 / 的路由

默认 route 遵从模糊匹配
设置 extra 遵从精确匹配

vue

vue

vue

一套构建用户界面的前端框架

  • 数据驱动视图
  • 双向数据绑定

MVVM:Model-View-ViewModel

Model 数据源

View DOM 结构

ViewModal Vue 实例

创建 Vue 实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const app = new Vue({
// Vue实例挂载对象,接收一个选择器
// 若匹配多个DOM对象,取匹配到的第一个DOM对象
el: "#app",
// 普通属性
data: {
msg: "",
},
// 计算属性:带返回值的方法
computed: {},
// 监听器
watch: {},
// 普通方法
methods: {},
// 过滤器
filters: {},
});

指令结构

指令:参数:修饰符

v-on:submit.prevent=""

文本

“Mustache”语法 {{ }} v-text

<span>{{msg}}</span> 只能用于内容节点

<span v-text="msg"></span> 会覆盖内部文本

v-once 单次渲染

原始 HTML

  • v-html

<span v-html="msg"></span> 会覆盖内部内容

避免使用,可能会发生 XSS 攻击存在安全风险

绑定 attr

  • v-bind

<a v-bind:href='url'></a>

简写 <a :href='url'></a>

计算属性

computed 对象

属性需为一个函数,并返回相应的值

使用时同正常的 data 属性即可

1
2
3
4
5
computed: {
val1: function () {
return `the number is ${this.val0} in the input box`;
}
}

其是依赖于响应式依赖进行缓存的,仅在其相应式依赖改变时才重新计算,因而可以提高性能

可以添加 setter 属性,默认只针对 getter 属性,这样可以同时更新 data 中数据

1
2
3
4
5
6
7
8
9
10
computed: {
val1: {
get: function () {
return `the number is ${this.val0} in the input box`;
},
set: function (val_1) {
this.val0 = val_1;
}
}
}

侦听属性

watch 对象

1
2
3
4
5
6
7
8
9
10
11
watch: {
// 方法形式
val0: function (newData, oldData) {
},
// 对象形式
val1: {
handler (newVal, oldVal) {},
immediate: true,
},
deep: true,
},

实质是一个函数,函数名是监听的变量名

  • immediate 选项

立即以表达式当前值触发回调

  • deep 选项

用于监听对象内部值的变化

若侦听特殊格式变量,可包裹单引号 如’info.id’ () {}

计算属性与侦听属性区别,计算属性根据其响应式属性的改变而改变,侦听属性根据其监视的属性的改变而修改相应的属性

绑定事件

  • v-on

<a v-on:click='handle_click'></a>

简写 <a @click='handle_click'></a>

  • 动态事件

<a @[event]='handle_click'></a>

  • 传参

<a @click='handle_click(1)'></a>

  • 传原生 DOM 事件
    $event

<a @click='handle_click($event)'></a>

实际方法无参时可以不用该方法,但有参数时必须使用该方法

  • 事件修饰符

  • prevent 阻止事件默认行为

  • stop 阻止事件传播

  • once 使事件仅触发一次

  • self 仅在触发事件的元素为绑定的元素本身时起效

  • capture 捕获事件模式:比内部元素绑定事件处理方法优先处理

  • passive 预先完成事件的默认行为而不是等待事件处理方法完成

修饰符可以串联使用

鼠标修饰符

  • left
  • right
  • middle

分别仅在点击鼠标相应侧按键时起效

按键修饰符

  • 可以指定为相应的键码才起效

.enter .tab .delete .esc .space .up .down .left .right

系统修饰符

  • exact 控制仅为给定的系统修饰符触发的事件
  • ctrl alt shift meta 控制需按下对应的按键才可触发事件

绑定表单

v-model

表单 <input><textarea><select> 元素有效

会忽略所有表单元素的 valuecheckedselected attribute 的初始值,故需在 data 中声明数据的初始值

  • text 和 textarea 元素使用 value property 和 input 事件
  • checkbox 和 radio 使用 checked property 和 change 事件
  • select 字段将 value 作为 prop 并将 change 作为事件

修饰符

  • number 自动转为数值类型
  • trim 自动过滤字符串两端空格符
  • lazy 改为在 change 事件后同步而不是默认的 input 事件后同步,即输入时失去或获得焦点才会触发事件

条件绑定

  • v-if truthy 值显示,falsy 值不显示

实质惰性渲染

  • v-show truthy 值显示,falsy 值不显示

实质仍渲染,通过 display 属性控制

若经常切换显示与否用 v-show,否则用 v-if;可以大幅提高性能

1
2
3
<div v-if="val === 0">0</div>
<div v-else-if="val === 1">1</div>
<div v-else>other</div>
  • :key 可以用于强制区别元素对象

循环绑定

  • v-for

  • :key 建议绑定 key 属性,并使用独一无二的值作为 key 的值 一般需为字符串或数字类型

1
<div v-for="(item, index) in array">{{index + ' : ' + item}}</div>

过滤器

filters

常用于实现文本格式化

可以用于插值表达式或 v-bind 属性

  • 语法

{{ message | capitalize }}

v-bind:id="rawId | formatId"

前一个是定义的变量,后一个是定义的过滤器方法,接收唯一一个参数为变量

  • 定义过滤器方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 局部过滤器
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}

// 全局过滤器
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
  • 其他玩法

过滤器串联 {{ message | filterA | filterB }}

过滤器接收参数 {{ message | filterA('arg1', arg2) }}

默认 message 是第一个参数,’arg1’是第二个参数,arg2 是第三个参数 da

SPA 单页面应用程序 & vue-cli

vue-cli 用于简化使用 webpack 创建 vue 项目的过程

  • 创建 vue 项目
    vue create PROJECT_NAME

  • vue 项目目录

  1. src:
    1. main.js:项目入口脚本文件
    2. App.vue:项目根组件
    3. assets:项目静态资源 如 css 样式表、图片资源
    4. components:组件
  2. public:
    1. favicon.ico:项目网页图标
    2. index.html:项目页面文件
  • vue 项目运行流程

通过 main.js 把 App.vue 渲染到 index.html 的指定位置

导入 vue
import Vue from 'vue';

导入 app 模板
import App from './App.vue';

1
2
3
4
5
// 添加 Vue 实例
new Vue({
// 渲染 render 函数指定的组件
render: (h) => h(App),
});

使用 $mount() 代替 el 属性绑定 DOM 对象

组件

使用 vue 后缀名文件定义独立组件

  1. 注册组件

    全局:建议注册于入口文件 main.js

1
2
3
Vue.component("my-component-name", {
// ... options ...
});

局部:注册于预期使用的区域

1
2
3
4
5
6
7
new Vue({
components: {
"com-1": {
/* options */
},
},
});
  1. 独立组件文件

    • template 组件模板结构
    • script 组件 js 行为
    • style 组件样式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
<div></div>
</template>
<script>
export default = {
name: 'my-component-name',
data: function () {
return {};
},
watch: {},
computed: {},
filters: {},
// props: ['my-prop-name'],
props: {
'my-prop-name' : {
default: 'default-value',
},
},
};
</script>
<style></style>
  1. 注意点

    • 组件应拥有一个根元素
    • 组件内部 data 必须是返回包含数据的对象的函数
    • 指定 style 的类型 <style lang="less">
    • 组件封装后是相互独立的,使用时具有父子关系
  2. 导入 vue 文件方法

1
2
3
4
5
6
7
8
import Test from "./components/test.vue";
export default {
name: "App",
// 声明使用Test组件
components: {
Test,
},
};
  1. 组件属性 props

    大多数属性同 Vue 实例对象

    • name: String 组件名称
    • props: Array | Object 组件自定义属性
      可以直接在方法中使用,只读,可以绑定 v-bind 以动态修改自定义属性的值
      • default 规定属性的默认值
      • type 规定属性的类型
        String Number Boolean Array Object Date Function Symbol 一个自定义的构造函数
      • required 规定属性是否为必须的
  2. 样式冲突问题

    组件内的样式全局生效,可能会影响到整个 index 页面
    利用 scoped 设定 <style scoped>
    原理是通过自定义 HTML 属性结合 CSS 属性选择器实现
    /deep/ div 仅修改子组件的样式

组件生命周期

  • 生命周期:组件的运行阶段
  • 生命周期函数:Vue 的内置函数,按组件生命周期自动按次序执行
  1. 组件创建状态

    • new Vue()
    • init events & lifecycle:初始化事件与生命周期函数
    • beforeCreate:尚未初始化数据方法
    • init injections & reactivity:初始化 props、data、methods
    • created:尚未形成实例模板结构【常用】
    • 基于数据和模板,在内存中编译生成 HTML 结构
    • beforeMount:即将编译好的 HTML 结构渲染至浏览器中
    • 用内存中编译完成的 HTML 结构替换掉 el 属性指定的 DOM 元素
    • mounted:已将编译好的 HTML 结构渲染至浏览器中,DOM 树已存在当前组件【常用】
  2. 组件运行状态

    • beforeUpdate:即将根据变化后最新的数据重新渲染组件的模板结构
    • 根据变化后最新的数据重新渲染组件的模板结构
    • updated:已将根据变化后最新的数据重新渲染组件的模板结构【常用】
  3. 组件销毁阶段

    • beforeDestroy:即将销毁组件
    • destroyed:已将组件销毁

生命周期

组件数据共享

  • 父->子 自定义属性 props

  • 子->父 自定义事件 $emit()

  • 兄弟<->兄弟 EventBus

利用 vue 实例中转,使用 bus.$emit() 触发自定义事件,使用bus.$on() 注册自定义事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// son
export default {
data() {
return {
i = 0;
};
},
methods: {
a() {
this.i++;
this.$emit('e', this.i);
},
},
};
// fa
// <Son @e='f'></Son>
export default {
data() {
return {
j = 0;
};
},
methods: {
f(v) {
this.j = v;
},
},
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// send data
import bus from './eventBus.js';
export default {
methods: {
send_msg() {
bus.$emit('share', /* data */);
},
},
}
// receive data
import bus from './eventBus.js';
export default {
created() {
bus.$on('share', (/* data */) => {
/* do something with data */
});
},
}
// eventBus.js
import Vue from 'vue';
export default new Vue();

操作 DOM 元素

ref 引用
默认 vue 组件实例包含 $refs 属性,包含组件内所有的设置 ref 属性的 DOM 元素引用,其为一对象,键名是 ref 的值,键值即为相应的 DOM 对象

1
2
3
4
/* <component ref="name"></component> */
fun() {
// using this.$refs.name
}

this.$nextTick() 将回调函数推迟至下一个 DOM 更新周期后执行

动态组件

利用<component></component>实现动态组件渲染

1
<component is="Left"></component> <component :is="comType"></component>
  • is 属性指定预期渲染的组件的名称,可以绑定变量实现动态切换使用的组件
  • 可以用<keep-alive>包裹组件,使之能在失活时缓存,从而可以高效重复使用组件
    • mount:
      • activated() 钩子 组件被激活
      • deactivated() 钩子 组件被缓存
    • props:
      • include 仅名称匹配的组件被缓存
      • exclude 任意名称匹配的组件不被缓存
      • 注意 include 与 exclude 不应同时使用

插槽

普通插槽

将组件内部在使用组件时插入内容时提供占位符

1
2
3
4
5
6
7
8
<!-- 组件 -->
<template>
<div>
<slot></slot>
</div>
</template>
<!-- 文件 -->
<Com> g </Com>

使用 <slot></slot> 声明一个插槽区域

内容使用 v-slot: 指令,且应用在 template 标签上,内部放置填充的内容
v-slot:default 可简写为 #default

编译时,插槽内使用的数据,父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的

后备内容

可以在组件内的插槽的 slot 标签内放入内容,指定若未给出应插入内容时的渲染内容

1
2
3
4
5
6
7
8
<!-- 组件 -->
<template>
<div>
<slot>default value</slot>
</div>
</template>
<!-- 文件 -->
<Com> given value </Com>

具名插槽

具有多个插槽的组件,需要指定插槽的名称,才可以正确地插入部件

通过指定 name 属性实现对插槽进行区别, name 属性默认值为 default

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- 组件 -->
<template>
<div>
<p>t</p>
<slot name="s1"></slot>
<slot name="s2"></slot>
</div>
</template>
<!-- 文件 -->
<Com>
<template v-slot:s1>
<p>s1</p>
</template>
<template v-slot:s2>
<p>s2</p>
</template>
</Com>

可以在组件内指定插槽的默认内容

作用域插槽

通过插槽自子元素组件向父元素传参

1
2
3
4
5
6
7
8
9
10
<!-- 子组件 -->
<span>
<slot v-bind:user="user"> {{ user.lastName }} </slot>
</span>
<!-- 父组件 -->
<current-user>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</template>
</current-user>

自定义指令

  • 私有自定义指令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 使用
<div v-color="color">color</div>;
export default {
// 私有自定义指令声明在该节点之下np
directives: {
color: {
// 首次绑定时调用
bind(el, binding) {
el.style.color = binding.value;
},
// DOM 更新时调用
update(el, binding) {
el.style.color = binding.value;
},
},
/**
* 若binding与update相同时可简写为
* color(el, binding) {},
*/
},
};
  • 全局自定义指令
1
2
3
4
5
Vue.directive("colo", {
bind() {},
update() {},
});
Vue.directive("colo", function () {});
  • 钩子函数

    • bind 指令绑定到元素时调用
    • inserted 被绑定元素被插入父节点时调用
    • update 组件的 VNode 更新时调用
    • componentUpdated 组件的 VNode 及其子 VNode 全部更新时调用
    • unbind 指令自元素解绑时调用
  • 钩子函数参数

    • el 指令绑定的元素
    • binding 指令的一些属性

路由

hash 地址与组件之间的对应关系

初始化配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 创建实例对象
// @/src/router/index.js
import Vue from "vue";
import VueRouter from "vue-router";
Vue.use(VueRouter);
const router = new VueRouter();
export default router;
// 导入 App.vue
// @/App.vue
import router from "@/router"; // 相当于 import router from '@/router/index.js';
new Vue({
router,
/* ... */
}).$mount("#app");

模块化导入,给定文件夹,默认导入文件夹下的 index.js 文件

基本路由

规定占位符与切换组件

  • <router-view></router-view> 占位符,显示组件
  • <router-link to="/about">关于</router-link>路由的切换

定义路由关系

1
2
3
4
5
6
7
8
9
10
11
12
// 导入组件
import Home from "@/components/Home.vue";
// 声明路由关系
const router = new VueRouter({
routes: [
{
path: "/home",
component: Home,
},
// ...
],
});

路由重定向

1
2
3
4
5
6
7
8
9
const router = new VueRouter({
routes: [
{
path: "/",
redirect: "/home",
},
// ...
],
});

动态路由

使用动态参数实现相同组件不同路由

<router-link to="/about/${id}">关于</router-link>

1
2
3
4
5
6
7
8
9
10
const router = new VueRouter({
routes: [
{
path: "/movie/:id",
component: Movie,
props: true, // 配置利用 props 获取参
},
// ...
],
});

组件内部获取参数 {} = this.$route.params

props 方式:直接在 Vue 实例中的 props 中获取参数

  • 路径参数 this.$route.params
  • 查询参数 this.$route.query

path:仅路径部分 & fullPath:完全参数

嵌套路由

路由内部的路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const router = new VueRouter({
routes: [
{
path: "/about",
component: Home,
/**
* ! 重定向
* redirect: '/about/tab1',
*/
children: [
{
path: "tab1",
component: Tab1,
},
{
/**
* ! 默认子路由
*/
path: "",
component: Tab1,
},
],
// ...
},
],
});

声明式导航 & 编程式导航

  • 声明式:点击链接
    • <a> <route-link>
  • 编程式:调用 API 跳转
    • location
    • this.$route.push(${url}) 跳转至指定的地址,并增加一条历史记录
    • this.$route.replace(${url}) 跳转至指定的地址,并替换当前的历史记录
    • this.$route.go(${number}) 在浏览器记录中进行前进 or 后退
    • this.$route.push()
    • this.$route.back()

导航守卫

控制路由的访问权限

全局前置守卫

在所有路由触发时起效

1
router.beforeEach((to, from, next) => {});

接收一个回调函数参数
回调函数第一个参数代表将访问的对象,第二个参数代表将离开的对象,第三个代表调用允许的路由导航

调用 next()方法

  • next() 允许跳转
  • next(url) 强制跳转至指定的页面
  • next(false) 不允许跳转

eslint

检查代码的风格的一款插件

.eslintrc.js eslint的配置文件

  • quotes
  • key-spacing
  • comma-dangle
  • no-multiple-empty-lines
  • no-trailing-spaces
  • eol-last
  • spaced-comment
  • indent
  • space-before-function-paren

Vue3

typescript

typescript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282

/** TS变量类型 */
let an: any;
let str: string = '12';
let num: number = 20;
let flag: boolean = true;

let arr: number[] = [1];
let ar: Array<number> = [2];
let tuple: [string, number] = ['test', 10];

enum Color {
Red,
Green,
Blue,
};
let co: Color = Color.Red;

function hello(): void {
console.log('hello');
}

let nu: null;
let un: undefined;
let ne: never;

/** 类型断言 */
var num0: number = <number> <any> str;

/** 类型推断 */

/**
* 变量作用域
* - 全局作用域
* - 类作用域
* - 局部作用域
*/

/** 运算符 */

/** 条件 */

/** 循环 */

/** 函数 */
// 可选参数 默认参数 剩余参数
function add(x: number = 0, y: number = 0, z?: number/* 可选参数: 必须在参数列表最后 */, ...other: number[]): number {
return x + y + (z ?? 0) + add(...other);
}
const sub = (x: number, y: number): number => x - y
const add_plus: (x: number, y:number) => number = (x, y) => x + y;

// 匿名函数 自动执行函数 递归函数 箭头函数
var res = function(a: number, b: number) {
return a * b;
};
(() => console.log('Hello!'))();

// 函数重载

/** 字面量类型 */
// 使用具体值作为类型
let fu: '0' | '1' | '2' | '3' = '1';
const fv = 1;

/** Number String Boolean 包装类型 */

/** Array 数组 元组 Map */
// 数组
let arr1: number[] = [1, 2];
let arr2: Array<number> = [3, 4];
// 元组 Tuple
let position: [number, string, boolean] = [1, '2', true];
// Map
const m: Map<number, number> = new Map();

/** 联合类型 */
var union: number | number[];
union = 12;
union = [12, 34];

/** 枚举类型 */
enum Direction {
Up,
Down,
Left,
Right,
};
// 枚举成员值默认是自第一个值(默认为0)开始的数值,即默认为数字枚举
var dir: Direction = Direction.Up;
enum Direction1 {
Left = 10,
Right,
};
// 字符串枚举必须有初始值
enum Direction2 {
Up = 'Up',
Down = 'Down',
Left = 'Left',
Right = 'Right',
};

/** typeof */
var cc: typeof position;

/** 接口 interface */
// 描述一个对象类型
// 当然也可以使用 type 关键字声明
interface Person {
name: string,
age: number,
birth?: Date,
sayHi: string | string[] | (() => string),
}
var csy: Person = {
name: 'CSY',
age: 20,
birth: new Date(),
sayHi: (): string => 'Hi',
}
const ccc: {
name: string,
sex?: boolean,
} = {
name: 'ccc',
};
// 接口的继承
interface Human extends Person {
father: Person,
mother: Person
}

/** 类型推论 */
// 自动推断变量类型
// 1. 声明变量并初始化
// 2. 决定函数返回值
let c = 20;
function f(a: number, b:number) {
return a + b;
}
/** 类型断言 */
// (可类型推论变量类型)自行指定变量的类型
const alink1 = document.getElementById('link') as HTMLAnchorElement;
const alink2 = <HTMLAnchorElement>document.getElementById('link');

/**
* 类 对象
* - 构造函数
* - 实例属性及实例方法
* - 访问控制修饰符 public protected private
* - 继承 extends 类 | implements 接口
* - 只读 readonly (仅适用方法)
*/
abstract class Animal {}
class Human extends Animal implements Person {
public a: string;
protected b: number;
private c: boolean;

name = 'CSY';
age = 40;
birth = new Date();
sayHi = () => 'Hi';

readonly d: String;

constructor (v: boolean) {
super();
this.c = v;
};

static isHuman = (o: any) => typeof o === 'object' && o instanceof Human;

get e () {
return this.a + this.a
}
set e (s) {
this.a = s.toLowerCase();
}
}
const son: Human = new Human(true);

/**
* 类型兼容 不同名称相同结构的类型是等价的
*
* - 类 | 若A类型内容包含B类型内容(非严格包含),则A类型变量可赋值给B类型变量
* - 接口 | 若A类型内容包含B类型内容(非严格包含),则A类型变量可赋值给B类型变量
* 类与接口亦可相互兼容
* - 函数 | 若B函数参数表包含A函数参数表(非严格包含),则A类型函数可赋值给B类型函数;相同位置参数需相同或兼容(对象多数服从少数);返回值需相同或兼容(对象少数服从多数)
*/

/**
* 交叉类型(类似接口继承)
* 将多个类型组合为同一个类型
* 重复的属性会合并为联合类型,相当于重载
*/
interface Co1 {
a: number,
}
interface Co2 {
b: string,
}
type Co = Co1 & Co2;
const co0: Co = {
a: 12,
b: '',
};

/** 泛型 */
// 泛型方法
function print <T> (v: T): void {
console.log(v);
}
// T 相当于类型变量
// 具体类型需用户使用时指定
print<number>(10)
print<string | boolean>('')
// 某些情况下可自动类型推定
print(1)
// 类型约束 结合interface使用 extends
function print0 <T extends Array<string> | string[]> (v: T): void {
console.log(v);
}
function print1 <T, K extends keyof T> (v: T, k: K): void {
console.log(v[k]);
}
// keyof 关键字接受对象类型并生成键名称(字符串和数字)的联合类型

// 泛型接口
interface PrintInterface <T> {
do: (v: T) => void
}

// 泛型类
class PrintClass <T> {
value: T;
}

// 泛型工具类
// Partial<T> 创建一个类型且T中所有属性均可选
type partial = Partial<Person>
// Readonly<T> 创建一个类型且T中所有属性均只读
type readonly = Readonly<Person>
// Pick<T, K extends keyof T> 创建一个类型并从给定类型中选出一组属性
type pick = Pick<Person, 'name' | 'age'>
// Record<K extends keyof any, T> 构造一个对象类型,属性键为keys,属性类型为Type
type record = Record<'a' | 'b', string>

// 索引签名类型
interface Obj {
[K: string]: number,
}
// [K: string] 表示任意string类型属性名称均可作为对象出现,且属性值为number类型变量

// 映射类型 in 关键字和 keyof 关键字
type p = {
[K in 'x' | 'y' | 'z']: number
}
type q = {
[K in keyof Person]: string
}

// 索引查询类型
type props = { a: number };
type typeA = props['a'];

/** 命名空间(可嵌套) */
namespace n {
export interface Person {};

namespace nn {}
}
var d: n.Person = {};

// 单独引用ts文件
/// <reference path="SomeFileName.ts" />

/** 模块 */

/** 声明 */
declare var jQuery: (selector: string) => any;

ajax

ajax

AJAX

AJAX

Ajax 简介

AJAX = Asynchronous JavaScript And XML

  1. 网页中发生一个事件(页面加载、按钮点击)
  2. 由 JavaScript 创建 XMLHttpRequest 对象
  3. XMLHttpRequest 对象向 web 服务器发送请求
  4. 服务器处理该请求
  5. 服务器将响应发送回网页
  6. 由 JavaScript 读取响应
  7. 由 JavaScript 执行正确的动作(比如更新页面)

Ajax 使用

XMLHttpRequest 对象用于同后台服务器交换数据

1
2
3
4
5
6
7
8
9
10
11
12
13
let request = new XMLHttpRequest();

request.open('POST', 'https://www.baidu.com', true);

request.setRequestHeader('Content-Type', 'application/json');

request.onreadystatechange = function() {
if(this.readyState === 4 && this.status === 200) {
console.log(this.responseText)
}
}

request.send({});
  • readyState 请求状态
    • 0:已创建对象未调用open方法
    • 1:已调用open方法
    • 2:已调用send方法已接收响应头
    • 3:数据接收中
    • 4:请求完成,数据接收完成或失败
  • status 服务器响应状态
  • responseText 请求返回的数据

请求数据类型 Content-Type

  • application/x-www-form-urlencoded

url 末尾加, ? 接 = 连接的键值对, 以 & 分隔多个参数

https://www.baidu.com?id=1&name=Lily

中文字符等会进行 URL 编码

使用 decodeURL() 编码,encodeURL() 解码

Ajax 默认请求数据类型

  • application/json

json 数据类型

  • multipart/form-data

常用于上传文件

Ajax 新特性

  • 设置请求时限
1
2
3
4
5
6
// 请求时限
request.timeout = 3000;
// 超时回调函数
request.ontimeout = (e) => {
console.log(e);
}
  • 使用 FormData 对象管理表单
1
2
let data = new FormData();
data.append('key', value);
  • 上传文件
1
2
3
4
5
6
7
8
// 获取文件
let files = document.querySelector('input[type=file]').files;
// 检测文件是否已选中
if(files.length <= 0)
return alert('ERROR');
// 创建 FormData 实例
let data = new FormData();
data.append('file', files[0]);
  • 获取数据传输进度信息
1
2
3
4
5
6
7
8
request.upload.onprogress = function (e) {
// lengthComputable 表示上传的资源是否具有可计算的长度
if(e.lengthComputable) {
// loaded 已传输的子节
// total 需传输的总子节
let percentComplete = Math.ceil((e.loaded / e.total) * 100);
}
}

jQuery 的 Ajax

  • $.ajax() 方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$('#button').on('click', function () {

const files = $('#file')[0].files;
if(files.length <= 0) {
return;
}

const data = new formData();
data.append('file', files[0]);

$.ajax({
method: 'POST',
url: 'https://www.baidu.com',
data: data,
// 内容编码类型
// 默认值: "application/x-www-form-urlencoded"
contentType: false,
// 是否进行url编码
// 默认值: true
processData: false,
success: function (res) {
console.log(res);
},
});

});
  • $(document).ajaxStart() 方法

在 Ajax 请求发送前执行函数

1
2
3
$(document).ajaxStart(function () {
$('#loading').show();
});
  • $(document).ajaxStop() 方法

在 Ajax 请求结束执行函数

axios

专注于网络数据请求的库

目前最主流的

官方网站

  • axios.get & axios.post
1
2
3
4
5
6
7
8
9
10
11
12
axios.get(url, params)
.then(function (res) {
// 处理成功情况
console.log(res);
})
.catch(function (err) {
// 处理错误情况
console.log(err);
})
.then(function () {
// 总是会执行
});

axios.get(url[, config])

axios.post(url[, data[, config]])

  • axios({})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// promise 语法
axios({
url: '',
method: '',
params: {}, // GET 数据:url参数
data: {}, // POST 数据:默认json参数对象
}).then(res => {
// do something with res.data
});

// async-await 语法
const {data} = await axios({
url: '',
method: '',
params: {},
data: {},
});
// do something with data
regex

regex

正则表达式

正则表达式是使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串的搜索模式

语法

/正则表达式主体/修饰符(可选)

字符串方法
  • search() 搜索字符串,返回匹配的字符串下标或-1
1
'123456'.search(/234/)   // 1
  • replace() 替换匹配的字符串,返回修改后的字符串
1
'123456'.replace(/345/, 'abc')   // 12abc6
  • split() 从指定位置分割字符串,返回一个数组
  • match() 搜索字符串,返回由所有子串组成的数组或null
正则表达式修饰符
  • i 忽略区别大小写
  • g 执行全局匹配
  • m 执行多行匹配
正则表达式元字符
  • . 查找单个非换行符字符

  • \d 查找数字

  • \s 查找空白字符

  • \b 匹配单词边界

  • \w 查找数字、大小写字母及下划线

正则表达式量词
  • n+ 匹配一个或多个字符串n
  • n* 匹配零个或多个字符串n
  • n? 匹配零个或一个字符串n
  • ^ 匹配字符串开始(第一个字符)
  • $ 匹配字符串结束(最后一个字符)
正则表达式括号
  • [0-9] 匹配任何0-9数字
  • [a-zA-Z] [A-z] 匹配任意大小写字母
  • [abc] 查找[]内的任意字符
  • [^abc] 查找[]外的任意字符
  • (x|y) 查找()内任意选项
RegExp 对象及其方法
  • test() 匹配字符串是否符合给定模式

返回一个布尔值

  • exec() 匹配字符串中正则表达式的匹配

返回一个包含搜索结果数组,未查找到返回null

参考链接

MDN 正则表达式

菜鸟教程 正则表达式

W3school 正则表达式

jquery

jquery

jQuery

简介

官方文档

https://jquery.com/

内容

jQuery JavaScript函数库

jQuery文件结构(function() {} ()),实质是一个自执行函数,给window对象添加一个jQuery属性和$属性

$是一个函数,传一个匿名函数即入口函数;传一个字符串即选择器;传一个dom对象即jQuery对象

可以用jQuery代替$的使用

引入jQuery即执行该js文件内代码

入口函数

$(function() {}) 等价于 window.onload()

可以写多个jQuery入口函数,其执行时机快于window.onload:window.onload等待所有资源加载完毕后执行;jQuery入口函数只等待dom树加载完成

$(document).ready(function(){})入口函数

建议
  • 把所有 jQuery 代码置于事件处理函数中

  • 把所有事件处理函数置于文档就绪事件处理器中

  • 把 jQuery 代码置于单独的 .js 文件中

  • 如果存在名称冲突,则重命名 jQuery 库

jQuery对象

概念
  • jQuery对象是伪数组,实际是dom对象的一个包装集合

  • 通过jQuery($())包装DOM的对象后产生的对象,为jQuery独有

  • 与DOM对象无法相互使用彼此方法

  • 建议jQuery对象在变量名前加$

jQuery对象获取DOM对象
  • [index]
  • .get(index)
jQuery对象获取DOM对象
  • $()包装

jQuery事件

  • 触发点击事件 .click()

  • 设置点击事件 .click(function(){})

特别的,仅会返回符合条件的第一个属性值

  • 鼠标移入事件 .mouseover() .mouseenter()

特别的,over在移入其本身及其子元素都会触发,enter仅移入其本身才触发

  • 鼠标移出事件 .mouseleave .mouseout

特别的,out在移出其本身及其子元素都会触发,leave仅移出其本身才触发

事件添加

简单事件->bind事件->delegate事件->on事件

简单事件:click(function(){}) 不支持同时注册与动态注册

bind事件:.bind(‘click’, function(){}) 不支持动态注册

delegate事件:.delegate(‘selector‘, {click: function(){}})

on事件:

事件注册 $(selector).on(‘click’, function(){})

事件委托 $(selector).on(‘click’, ‘selector’, function() {})

事件解绑

unbind() 不推荐

undelegate() 不推荐

off() 推荐 无参

事件触发

trigger() 触发事件

事件对象

jQuery事件对象是对原生js事件对象的封装,已处理了兼容性

坐标
  • screenX|screenY 原点屏幕左上角
  • clientX|clientY 原点可见页面区域左上角
  • pageX|pageY 原点页面区域左上角
方法
  • stopPropagation() 阻止事件冒泡
  • preventDefault() 阻止浏览器默认行为

事件响应方法返回false,可阻止事件冒泡与浏览器默认行为

  • keyCode 获取按下键盘的键码

jQuery选择器

简单选择器
  • id选择器 $(‘#id‘)
  • 类名选择器 $(‘.class‘)
  • 元素选择器 $(‘tag’)
  • 通配选择器 $(‘*’)

选取当前元素 $(this)

复合选择器
  • 并集选择器 $(‘selector1‘, ‘selector2‘)
  • 交集选择器 $(‘selector1selector2‘)
关系选择器
  • 子运算选择器 $(‘father > son‘)

  • 后代元素选择器 $(‘grandfather son‘)

过滤选择器
  • $(‘:eq(index)’) 特定序号子元素选择
  • $(‘:odd’) 奇数子元素选择
  • $(‘:even’) 偶数子元素选择
筛选选择器/方法
  • .next() 找下一个兄弟元素
  • .prev() 找上一个兄弟元素
  • .eq(index) 查找指定下标的兄弟元素
  • .parent() 查找父元素
  • .siblings(selector) 查找不包含自身的兄弟元素
  • .find(selector) 后代选择器
  • .children(selector) 子类选择器

jQuery HTML元素操作

获取及设置元素内容属性
  • 设置元素内文本 .text(*String*) .text(function(i, origText) {return *string*})

    ​ 会覆盖内部所有内容包括子元素内容

    ​ 不会解析字符串中的HTML部分

    ​ 存在隐式迭代现象

    ​ 回调函数形式:回调函数由两个参数:被选元素列表中当前元素的下标,以及原始(旧的)值,然后以函数新值返回您希望使用的字符串

1
2
3
4
$("#test1").text(function(i,origText){
return "Old text: " + origText + " New text: Hello world!
(index: " + i + ")";
});
  • 获取元素内所有文本 .text()

  • 获取及设置元素内容 .html()

    同text

    可以解析设置内容的元素节点

  • 获取及设置表单字段的值 .val()

    同text

  • 创建节点 $()

    需要主动添加到页面内

获取及设置元素样式属性
  • 设置元素CSS属性 .css(‘property‘, value)

    ​ .css(‘property1‘: value1)

    ​ .css({‘property1‘: value1, ‘property2‘: value2})

    修改与添加

  • 获取元素 CSS属性内容 .css(‘property‘)

1
2
3
4
5
6
7
8
$('#box1').css('width', '300px')
$('#box1').css('width', 300)

$('#box1').css({
width: 300,
'height': '300px',
'background-color': 'green'
})
  • 获取和设置元素的属性值 .attr()

    同css,回调函数同text

  • 移除属性值 .removeAttr(‘tag‘)

  • 设置布尔类型的属性:即元素标签内添加起效,不添加不起效的 .attr(‘tag‘)

获取元素尺寸
  • 获取或设置元素宽高 .width() .height()
  • 获取元素含内边距宽高 .innerwidth() .innerheight()
  • 获取元素含内边距及边框宽高 .outerwidth() .outerheight()
  • 获取元素含内外边距及边框宽高 .outerwidth(true) .outerheight(true)
获取元素位置
  • 获取元素距document位置 .offset()

    返回对象,包括top和left的值

  • 获取元素距设置定位属性的父元素offsetParent的位置 .position()

    返回值情况同offset

插入元素
  • 在元素开头结尾插入内容 .prepend(string1, …) .append(string1, …)

    $("p").append("Some appended text.");

​ .appendTo() .prependTo()

$(content).appendTo(selector)

  • 在元素之前之后插入元素 .before() .after()

    $("img").after("Some text after");

删除元素
  • 删除元素及其子元 素 .remove() .remove(selector)

    $("#div1").remove();

    $("p").remove(".italic"); 过滤

  • 删除元素子元素 .empty()

    $("#div1").empty();

获取及设置类class
  • 添加类 .addClass()

    $("#div1").addClass("important");

    $("div").addClass("important blue");

  • 移除类 .removeClass()

    $("h1,h2,p").removeClass("blue");

    $("div").addClass("important blue");

    $("h1,h2,p").removeClass();

  • 添加&删除类 .toggleClass()

  • 判断类的存在 .hasClass()

    返回布尔值

    $("#div1").hasClass("important");

其他
  • 查询并设置元素内容被卷曲出去的宽高度 scrollLeft() scrollTop()

    即元素的子元素宽高度超出元素本身的宽高度

  • 克隆元素 .clone()

    克隆的节点需要主动添加至页面上

    参数true表示克隆事件,否则不克隆事件,默认不克隆

jQuery效果与方法

元素隐藏及显示
  • 隐藏元素 .hide()

  • 显示元素 .show()

  • 隐藏及显示元素 .toggle()

    无参数无动画效果,有参数有动画效果

    speed 参数规定隐藏/显示的速度,可以取以下值:”slow”、”normal”、”fast” 或毫秒

    callback 参数是 toggle() 方法完成后所执行的函数名称

    实质是修改display属性

元素淡入淡出
  • 淡入已隐藏元素 .fadeIn()

    $(selector).fadeIn(speed,callback);

  • 淡出可见元素 fadeOut()

    $(selector).fadeOut(speed,callback);

  • 淡入或淡出元素 fadeToggle()

    $(selector).fadeToggle(speed,callback);

  • 渐变为指定不透明度 fadeTo()

    $(selector).fadeTo(speed,opacity,callback);

    实质是修改opacity属性

元素滑动
  • 向下滑动 .slideDown()

    $(selector).slideDown(speed,callback);

  • 向上滑动 .slideUp()

    $(selector).slideUp(speed,callback);

  • 向下或向上滑动 .slideToggle()

    $(selector).slideToggle(speed,callback);

    实质是修改padding和margin属性等

元素动画(自定义动画)
  • 自定义动画 .animate()

    $(selector).animate({params},speed,easing,callback);

    easing 可选 规定在不同的动画点中设置动画速度的 easing 函数(swing缓动 或 linear匀速)

    可以定义相对值(该值相对于元素的当前值),在值的前面加上 += 或 -=

  • 停止动画 .stop()

    $(selector).stop(stopAll,goToEnd);

    可选的 stopAll 参数规定是否应该清除动画队列,默认是 false,即仅停止活动的动画,允许任何排入队列的动画向后执行

    可选的 goToEnd 参数规定是否立即完成当前动画。默认是 false

其他
  • 释放 $ 标识符的控制,并返回对$的引用,可创建新的jQuery对象 $.noConflict()

jQuery遍历

祖先
  • parent() 获取给定元素的直接父元素

  • parents() 获取给定元素的所有祖先元素,直至文档根元素html

    允许参数,以过滤搜索祖先元素

  • parentsUntil() 获取直至给定元素间的所有祖先元素

后代
  • children() 获取给定元素的所有直接子元素

    可添加参数过滤搜索

  • find() 获取给定元素的后代元素

    必须添加参数决定搜索范围

兄弟
  • siblings() 获取给定元素的所有兄弟元素,不包括原给定元素
  • next() 返回给定元素的下一个兄弟元素
  • nextAll() 返回给定元素的之后所有兄弟元素
  • nextUntil() 返回给定元素与给定参数间所有跟随的同胞元素
  • prev()
  • prevAll()
  • prevUntil()
过滤
  • first() 选取首个元素
  • last() 选取最后一个元素
  • eq() 选取指定下标的元素,接受参数代表下标
  • filter() 选取符合给定规则的所有元素
  • not() 选取不符合给定规则的所有元素

jQuery Ajax方法

load() 方法

从服务器加载数据,并把返回的数据放入被选元素中

$(selector).load(URL,data,callback);

必需的 URL 参数规定加载的 URL

可选的 data 参数规定与请求一同发送的查询字符串键/值对集合

可选的 callback 参数是 load() 方法完成后所执行的函数名称

1
2
3
4
5
6
7
8
9
$("#div1").load("demo_test.txt");
$("#div1").load("demo_test.txt #p1");

$("#div1").load("demo_test.txt",function(responseTxt,statusTxt,xhr){
if(statusTxt=="success")
alert("外部内容加载成功!");
if(statusTxt=="error")
alert("Error: "+xhr.status+": "+xhr.statusText);
});
get() 方法

通过 HTTP GET 请求从服务器上请求数据

$.get(URL,callback);

必需的 URL 参数规定请求的 URL

可选的 callback 参数是请求成功后所执行的函数名

第一个回调参数存有被请求页面的内容,第二个回调参数存有请求的状态

1
$.get("demo_test.asp",function(data,status){});
post() 方法

通过 HTTP POST 请求从服务器上请求数据

$.post(URL,data,callback);

ajax() 方法

通过 HTTP 请求加载远程数据

可自选请求参数

其他

链式编程

$('div').width(100).height(100).css('backgroundColor', 'red');

返回值需均为相应的jQuery对象才能持续调用

end() 返回调用函数链的原始jQuery对象

each() 遍历jQuery对象集合,为各元素执行一次回调函数,回调函数第一个参数为下标,第二个·参数为对应元素的引用


:D 一言句子获取中...